/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"
#include "矢量计算.h"

#include "节点/插座/通用插座.h"
#include "节点/socket_utils.h"
#include "Context/数据转换.h"
#include "节点/节点树.h"

#include <节点/插座/list/list数值插座.h>
#include <节点/插座/list/list物体插座.h>
#include <节点/插座/list/list矢量插座.h>
#include <节点/插座/list/list物理物体插座.h>

#include <几何图形/图形相交.h>
#include <向量.h>
#include <matXX.h>
#include <core/几何计算/vec_array.h>
#include <core/几何计算/相交.h>
#include <core/geometry.h>

#include "计算类JIT函数.h"


const std::vector<S_标题和图标> 轴向平面icos = {
	{u"X_YZ平面",u""},
	{u"Y_XZ平面",u""},
	{u"Z_XY平面",u""},
};




static void f_射线网格相交(const std::vector<S_Mesh*>& meshs, const std::vector<S_线段>& data, std::vector<vec3>& outData) {
	auto* p_Mesh = meshs.data();
	uint32 num = meshs.size();

	auto* p_lines = data.data();
	uint32 lineNum = data.size();
	for (uint32 i = 0; i < num; ++i) {
		std::vector<vec3> 顶点;
		std::vector<uvec3> 索引;
		f_surface_get顶点坐标(p_Mesh[i], 顶点);
		f_surface_get顶点索引(p_Mesh[i], 索引);

		vec3* vert = 顶点.data();
		uvec3* index = 索引.data();
		uint32 faceNum = 索引.size();

		for (uint32 k = 0; k < lineNum; ++k) {
			vec3 dir = vec_normalize2(p_lines[k].end - p_lines[k].begin);
			for (uint32 j = 0; j < faceNum; ++j) {
				vec3 交点 = {};
				
				vec3 edge1 = { 0.0f, 0.0f, 0.0f };
				vec3 edge2 = { 0.0f, 0.0f, 0.0f };
				edge1 = vec_sub(顶点[index[j].y], 顶点[index[j].x]);
				edge2 = vec_sub(顶点[index[j].z], 顶点[index[j].x]);

				int32 是否相交 = f_intersect_射线三角形(顶点[index[j].x], edge1, edge2, p_lines[k].begin, dir, &交点);
				if (是否相交 > 0) {
					outData.push_back(交点);
				}
			}
		}
	}
}

static void f_射线网格相交反射(const std::vector<S_线段>& 线段, const S_点距八叉树& tree, std::vector<S_线段>& outData) {
	
	std::vector<vec3> 顶点;
	std::vector<uvec3> 索引;
	f_surface_get顶点坐标(((S_Mesh*)(tree.m_映射的数据)), 顶点);
	f_surface_get顶点索引(((S_Mesh*)(tree.m_映射的数据)), 索引);

	auto* p_lines = 线段.data();
	uint32 lineNum = 线段.size();
	for (uint32 i = 0; i < lineNum; ++i) {
		vec3 dir = vec_normalize2(p_lines[i].end - p_lines[i].begin);
		std::vector<S_八叉树子空间*> pathTree;
		f_空间划分_线段查子空间(&tree, p_lines[i], pathTree);

		for (const auto& e : pathTree) {
			uint32 单元数据num = ((std::vector<uint32>*)(e->m_数据))->size();
			uint32* indexs = ((std::vector<uint32>*)(e->m_数据))->data();

			for (uint32 k = 0; k < 单元数据num; ++k) {
				uvec3 index = 索引[indexs[k]];

				vec3 交点 = {};
				vec3 edge1 = { 0.0f, 0.0f, 0.0f };
				vec3 edge2 = { 0.0f, 0.0f, 0.0f };
				edge1 = vec_sub(顶点[index.y], 顶点[index.x]);
				edge2 = vec_sub(顶点[index.z], 顶点[index.x]);

				int32 是否相交 = f_intersect_射线三角形(顶点[index.x], edge1, edge2, p_lines[i].begin, dir, &交点);
				if (是否相交 > 0) {
					vec3 N = vec_normalize2(vec_cross(vec_normalize2(edge1), vec_normalize2(edge2)));
					outData.push_back({ 交点 , vec_Reflect(dir, N) });
				}
			}
		}
		
	}
}

static void f_线段相交三角形(const std::vector<S_线段>& 线段, const S_点距八叉树& tree, S_Mesh* outData) {
	
	std::vector<vec3> 顶点;
	std::vector<uvec3> 索引;
	f_surface_get顶点坐标(((S_Mesh*)(tree.m_映射的数据)), 顶点);
	f_surface_get顶点索引(((S_Mesh*)(tree.m_映射的数据)), 索引);

	std::vector<vec3> 新顶点;

	auto* p_lines = 线段.data();
	uint32 lineNum = 线段.size();
	for (uint32 i = 0; i < lineNum; ++i) {
		vec3 dir = vec_normalize2(p_lines[i].end - p_lines[i].begin);
		std::vector<S_八叉树子空间*> pathTree;
		f_空间划分_线段查子空间(&tree, p_lines[i], pathTree);

		for (const auto& e : pathTree) {
			uint32 单元数据num = ((std::vector<uint32>*)(e->m_数据))->size();
			uint32* indexs = ((std::vector<uint32>*)(e->m_数据))->data();

			for (uint32 k = 0; k < 单元数据num; ++k) {
				uvec3 index = 索引[indexs[k]];

				vec3 交点 = {};

				vec3 edge1 = { 0.0f, 0.0f, 0.0f };
				vec3 edge2 = { 0.0f, 0.0f, 0.0f };
				edge1 = vec_sub(顶点[index.y], 顶点[index.x]);
				edge2 = vec_sub(顶点[index.z], 顶点[index.x]);

				新顶点.push_back(顶点[index.x]);
				新顶点.push_back(顶点[index.y]);
				新顶点.push_back(顶点[index.z]);

			}
		}
	}

	auto 新索引 = f_Range<uint32>(0, 新顶点.size());
	f_mesh_fill顶点数据(outData, 新顶点);
	f_me_fill索引(outData, 新索引);
}






C_矢量计算节点::C_矢量计算节点(S_设备环境& ctx) : C_节点基类(DEF_矢量计算节点) {
	m_Ctx = ctx;
	f_setWName(u"矢量计算");
	

	C_插座基类* socket;
	DEF_创建Vec3_1D插座_I(u"源1");
	DEF_创建Vec3_1D插座_I(u"源2");

	DEF_创建Vec3_1D插座_O(u"out");

	m_计算方式 = f_alloc_EnumProp(nullptr,
		//	0			1			2			3			4
		{ {u"+", u""}, {u"-", u""}, {u"*", u""}, {u"/", u""}, {u"叉积", u""},
		//	5			6			7				8			9			
		{u"复制", u""},
		},
		u"计算方式",
		0,
		nullptr
	);
	m_计算方式.m_私有 = true;
	
	m_是否改变原数据 = f_alloc_BoolProp(nullptr, u"是否改变原数据");
	m_是否改变原数据.m_私有 = true;
	f_prop_Bool(m_是否改变原数据) = false;

	m_执行代码 = f_alloc_BoolProp(nullptr, u"执行代码");
	m_执行代码.m_私有 = true;
	f_prop_Bool(m_执行代码) = false;

	
	f_构建代码_分配渲染器GPU属性变量(m_计算方式);
	f_构建代码_构建GPU插座变量(*f_get输入插座(1));
	f_构建代码_构建GPU插座变量(*f_get输入插座(2));
}

C_矢量计算节点::~C_矢量计算节点() {
	f_构建代码_释放渲染器GPU属性变量(m_计算方式);
	f_构建代码_释放GPU插座变量(*f_get输入插座(1));
	f_构建代码_释放GPU插座变量(*f_get输入插座(2));

	f_prop_Release(m_计算方式);
	
}

#define _DEF_两向量计算节点_插座类型转换_                                                                                           \
auto 接入的数据类型1 = socket1->f_get接入的数据类型();                                                                              \
auto 接入的数据类型2 = socket2->f_get接入的数据类型();                                                                              \
if (f_代码构建_是否为数组(接入的数据类型1) || f_代码构建_是否为数组(接入的数据类型2)) 创建数组 = true;	                            \
if(!socket1->f_isLink() && !socket2->f_isLink()) 创建数组 = false;																	\
if (创建数组) {																														\
	    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);                                      \
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec3_1D);                                      \
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);                                      \
}                                                                                                                                   \
else {                                                                                                                              \
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);                                         \
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec3);                                         \
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);                                         \
}                                                                                                                                   \
socket1 = f_get输入插座(1);                                                                                                         \
socket2 = f_get输入插座(2);                                                                                                         \


bool C_矢量计算节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	
	bool 创建数组 = false;
	_DEF_两向量计算节点_插座类型转换_;

	uint32 方式 = f_prop_enum(m_计算方式);
	if (创建数组) {
		const S_Vec3Array* v1 = DEF_Vec3插座_1D数据(socket1);
		const S_Vec3Array* v2 = DEF_Vec3插座_1D数据(socket2);

		S_Vec3Array* r = DEF_Vec3插座_1D数据(f_get输出插座(1));

		f_JIT_Fun_vec3s_c_vec3s(v1, v2, r, 方式);
		
	}
	else {
		auto& 结果 = DEF_Vec3插座数据(f_get输出插座(1));
		switch (方式) {
			case 0: {
				结果 = vec_add(DEF_Vec3插座数据(socket1), DEF_Vec3插座数据(socket2));
				break;
			}
			case 1: {
				结果 = vec_sub(DEF_Vec3插座数据(socket1), DEF_Vec3插座数据(socket2));
				break;
			}
			case 2: {
				结果 = vec_mul(DEF_Vec3插座数据(socket1), DEF_Vec3插座数据(socket2));
				break;
			}
			case 3: {
				结果 = vec_div(DEF_Vec3插座数据(socket1), DEF_Vec3插座数据(socket2));
				break;
			}
			case 4: {
				结果 = cross(DEF_Vec3插座数据(socket1), DEF_Vec3插座数据(socket2));
				break;
			}
		}
	}
	return false;
}

std::string C_矢量计算节点::f_编译(C_节点基类* rn, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放) {
	m_Code = "";
	m_ReleaseCode = "";
	std::string 新变量 = f_getName();

	std::string 参数[2];
	std::string 数量;

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	bool 创建数组 = false;
	bool 创建浮点 = false;
	
	socket1->f_isLink();

	auto* rt = f_getThis节点树();
	switch (rt->m_树类型) {
		case E_节点树类型::e_type_几何着色节点树:
		case E_节点树类型::e_type_并行节点树: 
		case E_节点树类型::e_type_着色节点树: {
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec3);

			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);
			socket1 = f_get输入插座(1);
			socket2 = f_get输入插座(2);

			m_Code += socket1->f_构建变量代码(0);
			m_Code += socket2->f_构建变量代码(0);

		
			m_Code += "vec3 " + 新变量 + ";\n";


			m_Code += "{\n";
			m_Code += "switch(" + f_代码构建_属性变量(m_计算方式, rt) + "){\n";

			m_Code += "case 0:\n";
			m_Code += 新变量 + " = " + socket1->f_getCode(0) + " + " + socket2->f_getCode(0) + ";\n";
			m_Code += "break;\n";

			m_Code += "case 1:\n";
			m_Code += 新变量 + " = " + socket1->f_getCode(0) + " - " + socket2->f_getCode(0) + ";\n";
			m_Code += "break;\n";

			m_Code += "case 2:\n";
			m_Code += 新变量 + " = " + socket1->f_getCode(0) + " * " + socket2->f_getCode(0) + ";\n";
			m_Code += "break;\n";

			m_Code += "case 3:\n";
			m_Code += 新变量 + " = " + socket1->f_getCode(0) + " / " + socket2->f_getCode(0) + ";\n";
			m_Code += "break;\n";

			m_Code += "case 4:\n";
			m_Code += 新变量 + " = cross(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ");\n";
			m_Code += "break;\n";

			m_Code += "}\n";


			f_代码构建_属性变量传至GPU(m_计算方式);
			f_su_数据拷贝到GPU(socket1);
			f_su_数据拷贝到GPU(socket2);

			m_Code += "}\n";
			break;
		}
		default: {
			_DEF_两向量计算节点_插座类型转换_;

			if (创建数组) {
				m_Code += DEF_S(S_Vec3Array*)" " + 新变量 + ";\n";
			}
			else {
				m_Code += "vec3 " + 新变量 + ";\n";
			}

			m_Code += "{\n";
			m_Code += socket1->f_构建变量代码(0);
			m_Code += socket2->f_构建变量代码(0);

			auto code1 = socket1->f_getCode(0);
			auto code2 = socket2->f_getCode(0);

			if (code1.empty() || code2.empty()) {
				m_编译成功 = false;
				return "";
			}

			std::string 运算类型代码 = f_代码构建_属性变量(m_计算方式, rt);
			if (创建数组) {
				m_Code += 新变量 + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "1") + ";\n";
				m_Code += DEF_S(f_JIT_Fun_vec3s_c_vec3s);
				m_Code += "(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + 新变量 + ", " + 运算类型代码 + ");\n";
			}
			else {
				m_Code += 新变量 + " = " + DEF_S(f_JIT_Fun_vec3_c_vec3);
				m_Code += "(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + 运算类型代码 + ");\n";
			}

			m_Code += m_ReleaseCode;
			m_Code += "}\n";
			break;
		}
	}

	
	f_get输出插座(1)->f_setCode(新变量);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(新变量));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(新变量);
	}
	return m_Code;
}

void C_矢量计算节点::f_getStr(std::vector<std::vector<std::u16string>>& 文本) {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	auto name = f_getWName();

	const S_Vec3Array* v1 = DEF_Vec3插座_1D数据(socket1);
	const S_Vec3Array* v2 = DEF_Vec3插座_1D数据(socket2);
	S_Vec3Array* r = DEF_Vec3插座_1D数据(f_get输出插座(1));

	
	uint32 offset = 0;
	std::vector<std::u16string> 输入(5);
	输入[0] = name;
	输入[1] = u"输入A";
	for (uint32 i = 0; i < v1->count; ++i) {
		输入[2] = u"x:" + f_浮点数值转宽字符串(v1->ptr_userData[i].x);
		输入[3] = u"y:" + f_浮点数值转宽字符串(v1->ptr_userData[i].y);
		输入[4] = u"z:" + f_浮点数值转宽字符串(v1->ptr_userData[i].z);
	}
	文本.push_back(输入);

	输入[0] = name;
	输入[1] = u"输入B";
	for (uint32 i = 0; i < v2->count; ++i) {
		输入[2] = u"x:" + f_浮点数值转宽字符串(v2->ptr_userData[i].x);
		输入[3] = u"y:" + f_浮点数值转宽字符串(v2->ptr_userData[i].y);
		输入[4] = u"z:" + f_浮点数值转宽字符串(v2->ptr_userData[i].z);
	}
	文本.push_back(输入);

	输入[0] = name;
	输入[1] = u"结果";
	for (uint32 i = 0; i < r->count; ++i) {
		输入[2] = u"x:" + f_浮点数值转宽字符串(r->ptr_userData[i].x);
		输入[3] = u"y:" + f_浮点数值转宽字符串(r->ptr_userData[i].y);
		输入[4] = u"z:" + f_浮点数值转宽字符串(r->ptr_userData[i].z);
	}
	文本.push_back(输入);
}

void C_矢量计算节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_计算方式, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_是否改变原数据, 下一次读取数据指针);
		下一次读取数据指针 = f_prop_Load(m_执行代码, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_矢量计算节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	S_文件块 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算方式, 块);
	f_prop_Save(m_是否改变原数据, 块);
	f_prop_Save(m_执行代码, 块);

	f_file_保存文件块(f, 文件块, 块);
}

void C_矢量计算节点::f_Copy(const C_节点基类* node) {
	C_节点基类::f_Copy(node);

	const C_矢量计算节点* scr = dynamic_cast<const C_矢量计算节点*>(node);
	if (scr) {
		f_prop_Bool(m_是否改变原数据) = f_prop_Bool(scr->m_是否改变原数据);
		f_prop_enum(m_计算方式) = f_prop_enum(scr->m_计算方式);
	}
}

C_节点基类* f_node_创建矢量计算节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_矢量计算节点(ctx);
}

C_节点基类* f_node_加载矢量计算节点(S_设备环境& ctx, FILE* f) {
	C_矢量计算节点* node = new C_矢量计算节点(ctx);
	return node;
}

void f_node_保存矢量计算节点(C_节点基类* n, FILE* f) {
	C_矢量计算节点* node = dynamic_cast<C_矢量计算节点*>(n);
}




C_矢量逻辑计算节点::C_矢量逻辑计算节点(S_设备环境& ctx) : C_节点基类(DEF_逻辑计算节点) {
	m_Ctx = ctx;
	f_setWName(u"逻辑运算");

	C_插座基类* socket;
	DEF_创建F32插座_I(u"源1", 0);
	DEF_创建F32插座_I(u"源2", 0);

	DEF_创建I8插座_O(u"out", 0);


	m_计算方式 = f_alloc_EnumProp(nullptr, {
		//	0			1			 2		      3		
		{u">", u""}, {u"<", u""},  {u">=", u""}, {u"<=", u""},

		//	4			5			 6			  7			  	
		{u"==", u""}, {u"!=", u""}, {u"&&", u""}, {u"||", u""}, 
		},
		u"计算方式",
		0,
		nullptr
	);
	m_计算方式.m_私有 = true;
}

C_矢量逻辑计算节点::~C_矢量逻辑计算节点() {
	f_prop_Release(m_计算方式);
}

std::string C_矢量逻辑计算节点::f_编译(C_节点基类* rn, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放) {
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();

	C_节点树* rt = f_getThis节点树();
	std::string 运算符;



	bool 创建数组 = false;
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	switch (socket1->f_get接入的数据类型()) {
		case E_值类型::e_Type_Vec3_1D:
		case E_值类型::e_Type_iVec3_1D:
		//case E_值类型::e_Type_UI32_1D:
			创建数组 = true;
			break;
	}
	switch (socket2->f_get接入的数据类型()) {
		case E_值类型::e_Type_Vec3_1D:
		case E_值类型::e_Type_iVec3_1D:
		//case E_值类型::e_Type_UI32_1D:
			创建数组 = true;
			break;
	}
	if (创建数组) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec3_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_I8_1D);

		m_Code += DEF_S(S_I8Array*)" " + name + ";\n";
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec3);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_I8);

		m_Code += DEF_S(int8)" " + name + ";\n";
	}
	socket1 = f_get输入插座(1);
	socket2 = f_get输入插座(2);


	m_Code += "{\n";

	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);

	auto 计算方式 = f_代码构建_属性变量(m_计算方式, f_getThis节点树());
	if (创建数组) {
		m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_F32_1D, "1");
		m_Code += DEF_S(f_JIT_Fn_逻辑计算m);
	}
	else {
		m_Code += DEF_S(f_JIT_Fn_逻辑计算);
	}
	m_Code += "(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + name + ", " + 计算方式 + ");\n";

	m_Code += m_ReleaseCode;
	m_Code += "}\n";


	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_矢量逻辑计算节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		switch (文件块.m_版本号) {
			case 0 << 32 | 1: {
				const uint8* 下一次读取数据指针 = 文件块.m_data;

				下一次读取数据指针 = f_prop_Load(m_计算方式, 下一次读取数据指针);
				break;
			}
		}
	}
	free(文件块.m_data);
}

void C_矢量逻辑计算节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算方式, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建矢量逻辑计算节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_矢量逻辑计算节点(ctx);
}

C_节点基类* f_node_加载矢量逻辑计算节点(S_设备环境& ctx, FILE* f) {
	C_矢量逻辑计算节点* node = new C_矢量逻辑计算节点(ctx);
	return node;
}

void f_node_保存矢量逻辑计算节点(C_节点基类* n, FILE* f) {
	C_矢量逻辑计算节点* node = dynamic_cast<C_矢量逻辑计算节点*>(n);
}




C_两向量转四元数节点::C_两向量转四元数节点(S_设备环境& ctx) : C_节点基类(DEF_两向量转四元数) {
	f_setWName(u"两向量到四元数");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建Vec3插座_I(u"向量1", nullptr);
	DEF_创建Vec3插座_I(u"向量2", nullptr);
	
	DEF_创建Vec4插座_O(u"四元数");


	m_计算方式 = f_alloc_EnumProp(nullptr, { 
	    {u"独立",				u""},
		{u"后一个减去前一个",	u""},
		{u"累加",				u""},
	}, u"向量标量计算");
	m_计算方式.m_私有 = true;
}

C_两向量转四元数节点::~C_两向量转四元数节点() {
}

#define _DEF_两向量转四元数计算节点_插座类型转换_                                                                                   \
if (socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D || socket2->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D) {     \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);                                          \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec3_1D);                                          \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec4_1D);                                          \
    创建数组 = true;                                                                                                                \
}                                                                                                                                   \
else {                                                                                                                              \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);                                             \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec3);                                             \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec4);                                             \
	创建数组 = false;                                                                                                               \
}                                                                                                                                   \
socket1 = f_get输入插座(1);                                                                                                         \
socket2 = f_get输入插座(2);                                                                                                          


bool C_两向量转四元数节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);



	auto& 向量1 = DEF_Vec3插座数据(f_get输入插座(1));
	auto& 向量2 = DEF_Vec3插座数据(f_get输入插座(2));

	auto& 四元数 = DEF_Vec4插座数据(f_get输出插座(1), 0);

	四元数 = f_graph_quat两向量(vec_normalize(向量1), vec_normalize(向量2));
	
	return false;
}

std::string C_两向量转四元数节点::f_编译(C_节点基类* rn, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放) {
	m_Code = "";
	m_ReleaseCode = "";

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	bool 创建数组 = false;
	_DEF_两向量转四元数计算节点_插座类型转换_


	std::string name = f_getName();
	f_get输出插座(1)->f_setCode(name);
	if (创建数组) {
		m_Code = DEF_S(S_Vec4Array);
		m_Code += "* " + name + ";\n";
	}
	else {
		m_Code = "vec4 " + name + ";\n";
	}

	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);

	if (创建数组) {
		m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec4_1D, f_代码构建_Array数组数量(socket1->f_getCode(0)));
		m_Code += DEF_S(f_math_quat两向量m);
		m_Code += "(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + name + ");\n";
	}
	else {
		m_Code += name + " = ";
		m_Code += DEF_S(f_graph_quat两向量);
		m_Code += "(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ");\n";
	}
	

	m_Code += m_ReleaseCode;
	m_Code += "}\n";

	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_两向量转四元数节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_计算方式, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_两向量转四元数节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算方式, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建向量转四元数节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_两向量转四元数节点(ctx);
}

C_节点基类* f_node_加载向量转四元数节点(S_设备环境& ctx, FILE* f) {
	C_两向量转四元数节点* node = new C_两向量转四元数节点(ctx);
	return node;
}

void f_node_保存向量转四元数节点(C_节点基类* n, FILE* f) {
	C_两向量转四元数节点* node = dynamic_cast<C_两向量转四元数节点*>(n);
}




C_合并XYZ节点::C_合并XYZ节点(S_设备环境& ctx) : C_节点基类(DEF_合并XYZ节点) {
	f_setWName(u"合并XYZ");
	m_Ctx = ctx;
	
	C_插座基类* socket;
	DEF_创建F32插座_I(u"X", nullptr);
	DEF_创建F32插座_I(u"Y", nullptr);
	DEF_创建F32插座_I(u"Z", nullptr);

	DEF_创建Vec3插座_O(u"矢量");

	f_构建代码_构建GPU插座变量(*f_get输入插座(1));
	f_构建代码_构建GPU插座变量(*f_get输入插座(2));
	f_构建代码_构建GPU插座变量(*f_get输入插座(3));
}

C_合并XYZ节点::~C_合并XYZ节点(){
}

bool C_合并XYZ节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	auto* socket3 = f_get输入插座(3);

	auto 接入的数据类型1 = socket1->f_get接入的数据类型();
	auto 接入的数据类型2 = socket2->f_get接入的数据类型();
	auto 接入的数据类型3 = socket3->f_get接入的数据类型();


	bool 创建数组 = false;
	bool 创建浮点 = false;
	switch (接入的数据类型1) {
		case E_值类型::e_Type_Array:
		case E_值类型::e_Type_UI32_1D:
		case E_值类型::e_Type_I32_1D:
		case E_值类型::e_Type_I8_1D:
		case E_值类型::e_Type_F32_1D: 创建数组 |= true; break;
	}

	switch (接入的数据类型2) {
		case E_值类型::e_Type_Array:
		case E_值类型::e_Type_UI32_1D:
		case E_值类型::e_Type_I32_1D:
		case E_值类型::e_Type_I8_1D:
		case E_值类型::e_Type_F32_1D: 创建数组 |= true; break;
	}

	switch (接入的数据类型3) {
		case E_值类型::e_Type_Array:
		case E_值类型::e_Type_UI32_1D:
		case E_值类型::e_Type_I32_1D:
		case E_值类型::e_Type_I8_1D:
		case E_值类型::e_Type_F32_1D: 创建数组 |= true; break;
	}


	if (创建数组) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_F32_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_F32_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 3, E_值类型::e_Type_F32_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_F32);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_F32);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 3, E_值类型::e_Type_F32);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);
	}
	socket1 = f_get输入插座(1);
	socket2 = f_get输入插座(2);
	socket3 = f_get输入插座(3);


	if (创建数组) {
		auto* r = DEF_Vec3插座_1D数据(f_get输出插座(1));

		const auto* x = DEF_F32插座_1D数据(socket1);
		const auto* y = DEF_F32插座_1D数据(socket2);
		const auto* z = DEF_F32插座_1D数据(socket3);

		uint32 num = DEF_Max(x->count, y->count);
		num = DEF_Max(num, z->count);
		uint32 x多例 = x->count >= num;
		uint32 y多例 = y->count >= num;
		uint32 z多例 = z->count >= num;

		f_core_array_resize((S_Array*)r, num);
		for (uint32 i = 0; i < num; ++i) {
			vec3 v;
			v.x = x多例 ? x->ptr_userData[i] : x->ptr_userData[0];
			v.y = y多例 ? y->ptr_userData[i] : y->ptr_userData[0];
			v.z = z多例 ? z->ptr_userData[i] : z->ptr_userData[0];
			r->ptr_userData[i] = v;
		}
	}
	else {
		auto& r = DEF_Vec3插座数据(f_get输出插座(1), 0);

		r.x = DEF_F32插座数据(socket1);
		r.y = DEF_F32插座数据(socket2);
		r.z = DEF_F32插座数据(socket3);
	}
	
	return false;
}

std::string C_合并XYZ节点::f_编译(C_节点基类* rn, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放) {
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();

	bool 创建数组 = false;
	bool 创建浮点 = false;

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	auto* socket3 = f_get输入插座(3);

	auto* rt = f_getThis节点树();
	switch (rt->m_树类型) {
		case E_节点树类型::e_type_几何着色节点树:
		case E_节点树类型::e_type_并行节点树: 
		case E_节点树类型::e_type_着色节点树: {
			m_Code += socket1->f_构建变量代码(0);
			m_Code += socket2->f_构建变量代码(0);
			m_Code += socket3->f_构建变量代码(0);

			socket1->f_upGPU块(0);
			socket2->f_upGPU块(0);
			socket3->f_upGPU块(0);

			m_Code += "vec3 " + name + " = vec3(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + socket3->f_getCode(0) + ");\n";
			break;
		}
		default : {
			std::string 参数[3];
			std::string 数量;


			C_节点树* rt = f_getThis节点树();
		

			auto 接入的数据类型1 = socket1->f_get接入的数据类型();
			auto 接入的数据类型2 = socket2->f_get接入的数据类型();
			auto 接入的数据类型3 = socket3->f_get接入的数据类型();



			switch (接入的数据类型1) {
			case E_值类型::e_Type_Array:
			case E_值类型::e_Type_UI32_1D:
			case E_值类型::e_Type_I32_1D:
			case E_值类型::e_Type_I8_1D:
			case E_值类型::e_Type_F32_1D: 创建数组 |= true; break;
			}

			switch (接入的数据类型2) {
			case E_值类型::e_Type_Array:
			case E_值类型::e_Type_UI32_1D:
			case E_值类型::e_Type_I32_1D:
			case E_值类型::e_Type_I8_1D:
			case E_值类型::e_Type_F32_1D: 创建数组 |= true; break;
			}

			switch (接入的数据类型3) {
			case E_值类型::e_Type_Array:
			case E_值类型::e_Type_UI32_1D:
			case E_值类型::e_Type_I32_1D:
			case E_值类型::e_Type_I8_1D:
			case E_值类型::e_Type_F32_1D: 创建数组 |= true; break;
			}



			bool 空链接插座 = true;

			if (socket1->f_isLink()) {
				创建浮点 |= f_代码构建_是否为单值浮点(接入的数据类型1);
				空链接插座 = false;
			}
			else {
				创建浮点 |= true;
			}
			if (socket2->f_isLink()) {
				创建浮点 |= f_代码构建_是否为单值浮点(接入的数据类型2);
				空链接插座 = false;
			}
			else {
				创建浮点 |= true;
			}
			if (socket3->f_isLink()) {
				创建浮点 |= f_代码构建_是否为单值浮点(接入的数据类型3);
				空链接插座 = false;
			}
			else {
				创建浮点 |= true;
			}

		
			if (创建数组 && !空链接插座) {
				if (创建浮点) {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_F32_1D);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_F32_1D);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 3, E_值类型::e_Type_F32_1D);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);
				
					m_Code += DEF_S(S_Vec3Array*)" " + name + ";\n";
				}
				else {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_I32_1D);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_I32_1D);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 3, E_值类型::e_Type_I32_1D);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_iVec3_1D);

					m_Code += DEF_S(S_iVec3Array*)" " + name + ";\n";
				}
				创建数组 = true;
			}
			else {
				if (创建浮点) {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_F32);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_F32);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 3, E_值类型::e_Type_F32);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);

					m_Code += DEF_S(vec3)" " + name + ";\n";
				}
				else {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_I32);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_I32);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 3, E_值类型::e_Type_I32);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_iVec3);

					m_Code += DEF_S(ivec3)" " + name + ";\n";
				}
				创建数组 = false;
			}
			socket1 = f_get输入插座(1);
			socket2 = f_get输入插座(2);
			socket3 = f_get输入插座(3);


			m_Code += "{\n";

			m_Code += socket1->f_构建变量代码(0);
			m_Code += socket2->f_构建变量代码(0);
			m_Code += socket3->f_构建变量代码(0);


			if (创建浮点) {
				m_Code += "uint32 num[3] = { 0, 0, 0 };\n";
				switch (socket1->m_Type) {
					case E_值类型::e_Type_UI32:
					case E_值类型::e_Type_I32:
					case E_值类型::e_Type_F32:
						m_Code += "float32 临时转换变量_合并元素X = " + socket1->f_getCode(0) + ";\n";
						m_Code += "float32* 合并元素X = &临时转换变量_合并元素X;\n";
						m_Code += "num[0] = 1;\n";
						break;
					case E_值类型::e_Type_F32_1D:
						m_Code += "float32* 合并元素X = (" + socket1->f_getCode(0) + ")->ptr_userData;\n";
						m_Code += "num[0] = " + f_代码构建_Array数组数量(socket1->f_getCode(0)) + ";\n";
						break;
				}

				switch (socket2->m_Type) {
					case E_值类型::e_Type_UI32:
					case E_值类型::e_Type_I32:
					case E_值类型::e_Type_F32:
						m_Code += "float32 临时转换变量_合并元素Y = " + socket2->f_getCode(0) + ";\n";
						m_Code += "float32* 合并元素Y = &临时转换变量_合并元素Y;\n";
						m_Code += "num[1] = 1;\n";
						break;
					case E_值类型::e_Type_F32_1D:
						m_Code += "float32* 合并元素Y = (" + socket2->f_getCode(0) + ")->ptr_userData;\n";
						m_Code += "num[1] = " + f_代码构建_Array数组数量(socket2->f_getCode(0)) + ";\n";
						break;
				}

				switch (socket3->m_Type) {
					case E_值类型::e_Type_UI32:
					case E_值类型::e_Type_I32:
					case E_值类型::e_Type_F32:
						m_Code += "float32 临时转换变量_合并元素Z = " + socket3->f_getCode(0) + ";\n";
						m_Code += "float32* 合并元素Z = &临时转换变量_合并元素Z;\n";
						m_Code += "num[2] = 1;\n";
						break;
					case E_值类型::e_Type_F32_1D:
						m_Code += "float32* 合并元素Z = (" + socket3->f_getCode(0) + ")->ptr_userData;\n";
						m_Code += "num[2] = " + f_代码构建_Array数组数量(socket3->f_getCode(0)) + ";\n";
						break;
				}

				if (创建数组) {
					m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "1");
					m_Code += DEF_S(f_vec3_合并)"(" + name + ", 合并元素X, 合并元素Y, 合并元素Z, num);\n";
				}
				else {
					m_Code += name + ".x = " + socket1->f_getCode(0) + ";\n";
					m_Code += name + ".y = " + socket2->f_getCode(0) + ";\n";
					m_Code += name + ".z = " + socket3->f_getCode(0) + ";\n";
				}
			}
			else {
			
				if (创建数组) {
					m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_iVec3_1D, "1");
					m_Code += DEF_S(f_JIT_ivec3_合并);
					m_Code += "(" + name + ", " + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + socket3->f_getCode(0) + "); \n";
				}
				else {
					m_Code += name + ".x = " + socket1->f_getCode(0) + ";\n";
					m_Code += name + ".y = " + socket2->f_getCode(0) + ";\n";
					m_Code += name + ".z = " + socket3->f_getCode(0) + ";\n";
				}
			}
		

			m_Code += m_ReleaseCode;
			m_Code += "}\n";
		}
	}
	
	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_合并XYZ节点::f_getStr(std::vector<std::vector<std::u16string>>& 文本) {
	auto* socket1 = f_get输出插座(1);
	auto& r = DEF_Vec3插座数据(socket1);
	std::vector<std::u16string> 输入(4);
	输入[0] = f_getWName();
	输入[1] = u"x:" + f_浮点数值转宽字符串(r.x);
	输入[2] = u"y:" + f_浮点数值转宽字符串(r.y);
	输入[3] = u"z:" + f_浮点数值转宽字符串(r.z);

	文本.push_back(输入);
}

C_节点基类* f_node_创建合并XYZ节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_合并XYZ节点(ctx);
}

C_节点基类* f_node_加载合并XYZ节点(S_设备环境& ctx, FILE* f) {
	C_合并XYZ节点* node = new C_合并XYZ节点(ctx);
	return node;
}

void f_node_保存合并XYZ节点(C_节点基类* n, FILE* f) {
	C_合并XYZ节点* node = dynamic_cast<C_合并XYZ节点*>(n);
}




C_分离XYZ节点::C_分离XYZ节点(S_设备环境& ctx) : C_节点基类(DEF_分离XYZ节点) {
	f_setWName(u"分离XYZ");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建Vec3插座_I(u"矢量", nullptr);

	DEF_创建F32插座_O(u"X", nullptr);
	DEF_创建F32插座_O(u"Y", nullptr);
	DEF_创建F32插座_O(u"Z", nullptr);

	f_构建代码_构建GPU插座变量(*f_get输入插座(1));
}

C_分离XYZ节点::~C_分离XYZ节点(){
}

bool C_分离XYZ节点::f_update() {
	f_su_插座类型切换到连入的插座类型(this, E_插座方向::e_插座Type_输入, 1);
	bool 创建浮点 = false;

	auto* rt = f_getThis节点树();

	auto* socket1 = f_get输入插座(1);
	
	if (rt->m_树类型 == E_节点树类型::e_type_着色节点树) {
		
	}
	else {
		auto 接入的数据类型1 = socket1->f_get接入的数据类型();


		switch (socket1->m_Type) {
		case E_值类型::e_Type_Vec3: {
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 2, E_值类型::e_Type_F32);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 3, E_值类型::e_Type_F32);

			auto& v = DEF_Vec3插座数据(socket1);
			DEF_F32插座数据(f_get输出插座(1)) = v.x;
			DEF_F32插座数据(f_get输出插座(2)) = v.y;
			DEF_F32插座数据(f_get输出插座(3)) = v.z;
			break;
		}
		case E_值类型::e_Type_Vec3_1D: {
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32_1D);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 2, E_值类型::e_Type_F32_1D);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 3, E_值类型::e_Type_F32_1D);

			auto* f1 = DEF_F32插座_1D数据(f_get输出插座(1));
			auto* f2 = DEF_F32插座_1D数据(f_get输出插座(2));
			auto* f3 = DEF_F32插座_1D数据(f_get输出插座(3));


			const auto* v = DEF_Vec3插座_1D数据(socket1, 0);
			f_core_array_resize((S_Array*)f1, v->count);
			f_core_array_resize((S_Array*)f2, v->count);
			f_core_array_resize((S_Array*)f3, v->count);
			for (uint32 i = 0; i < v->count; ++i) {
				f1->ptr_userData[i] = v->ptr_userData[i].x;
				f2->ptr_userData[i] = v->ptr_userData[i].y;
				f3->ptr_userData[i] = v->ptr_userData[i].z;
			}
			break;
		}
		default:
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 2, E_值类型::e_Type_F32);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 3, E_值类型::e_Type_F32);
			break;
		}
	}
	
	return false;
}

std::string C_分离XYZ节点::f_编译(C_节点基类* rn, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放) {
	m_Code = "";
	m_ReleaseCode = "";
	bool 创建浮点 = false;
	bool 创建数组 = false;

	auto* socket1 = f_get输入插座(1);
	if (socket1->f_isLink()) {
		f_su_插座类型切换到连入的插座类型(this, E_插座方向::e_插座Type_输入, 1);
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);
	}
	socket1 = f_get输入插座(1);


	
	std::string name = f_getName();
	std::string 新变量_X = name + "_X";
	std::string 新变量_Y = name + "_Y";
	std::string 新变量_Z = name + "_Z";


	

	auto* rt = f_getThis节点树();
	switch (rt->m_树类型) {
		case E_节点树类型::e_type_几何着色节点树:
		case E_节点树类型::e_type_并行节点树:
		case E_节点树类型::e_type_着色节点树: {
			socket1 = f_get输入插座(1);
			m_Code += socket1->f_构建变量代码(0);

			socket1->f_upGPU块(0);

			auto code = socket1->f_getCode(0, false);
			m_Code += "float " + 新变量_X + " = " + code + ".x;\n";
			m_Code += "float " + 新变量_Y + " = " + code + ".y;\n";
			m_Code += "float " + 新变量_Z + " = " + code + ".z;\n";
			break;
		}
		default: {
			auto 接入的数据类型1 = socket1->f_get接入的数据类型();


			if (f_代码构建_是否为数组(接入的数据类型1)) {
				创建数组 = true;
				创建浮点 = f_代码构建_是否为矢量数组浮点(接入的数据类型1);

				if (创建浮点) {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);

					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32_1D);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 2, E_值类型::e_Type_F32_1D);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 3, E_值类型::e_Type_F32_1D);


					m_Code += DEF_S(S_F32Array*)" " + 新变量_X + ";\n";
					m_Code += DEF_S(S_F32Array*)" " + 新变量_Y + ";\n";
					m_Code += DEF_S(S_F32Array*)" " + 新变量_Z + ";\n";
				}
				else {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_iVec3_1D);

					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_I32_1D);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 2, E_值类型::e_Type_I32_1D);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 3, E_值类型::e_Type_I32_1D);

					m_Code += DEF_S(S_I32Array*)" " + 新变量_X + ";\n";
					m_Code += DEF_S(S_I32Array*)" " + 新变量_Y + ";\n";
					m_Code += DEF_S(S_I32Array*)" " + 新变量_Z + ";\n";
				}

			}
			else {
				创建浮点 = f_代码构建_是否为矢量浮点(接入的数据类型1);

				if (创建浮点) {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);

					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 2, E_值类型::e_Type_F32);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 3, E_值类型::e_Type_F32);

				}
				else {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_iVec3);

					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_I32);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 2, E_值类型::e_Type_I32);
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 3, E_值类型::e_Type_I32);

				}

				if (创建浮点) {
					m_Code += "float32 " + 新变量_X + " = 0;\n";
					m_Code += "float32 " + 新变量_Y + " = 0;\n";
					m_Code += "float32 " + 新变量_Z + " = 0;\n";
				}
				else {
					m_Code += "int32 " + 新变量_X + " = 0;\n";
					m_Code += "int32 " + 新变量_Y + " = 0;\n";
					m_Code += "int32 " + 新变量_Z + " = 0;\n";
				}
			}


			socket1 = f_get输入插座(1);


			m_Code += "{\n";
			m_Code += socket1->f_构建变量代码(0);

			auto inCode = socket1->f_getCode(0);
			if (创建数组) {
				if (创建浮点) {
					m_Code += 新变量_X + " = " + f_代码构建_创建Array(E_值类型::e_Type_F32_1D, "1");
					m_Code += 新变量_Y + " = " + f_代码构建_创建Array(E_值类型::e_Type_F32_1D, "1");
					m_Code += 新变量_Z + " = " + f_代码构建_创建Array(E_值类型::e_Type_F32_1D, "1");


					m_Code += DEF_S(f_JIT_vec3_分离);
					m_Code += "(" + 新变量_X + ", " + 新变量_Y + ", " + 新变量_Z + ", " + inCode + ");\n";
				}
				else {
					m_Code += 新变量_X + " = " + f_代码构建_创建Array(E_值类型::e_Type_I32_1D, "1");
					m_Code += 新变量_Y + " = " + f_代码构建_创建Array(E_值类型::e_Type_I32_1D, "1");
					m_Code += 新变量_Z + " = " + f_代码构建_创建Array(E_值类型::e_Type_I32_1D, "1");


					m_Code += DEF_S(f_JIT_ivec3_分离);
					m_Code += "(" + 新变量_X + ", " + 新变量_Y + ", " + 新变量_Z + ", " + inCode + ");\n";
				}
			}
			else {
				m_Code += 新变量_X + " = " + inCode + ".x;\n";
				m_Code += 新变量_Y + " = " + inCode + ".y;\n";
				m_Code += 新变量_Z + " = " + inCode + ".z;\n";
			}

			m_Code += m_ReleaseCode;
			m_Code += "}\n";
			break;
		}
	}
	
	f_get输出插座(1)->f_setCode(新变量_X);
	f_get输出插座(2)->f_setCode(新变量_Y);
	f_get输出插座(3)->f_setCode(新变量_Z);

	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(新变量_X) + f_代码构建_销毁数组(新变量_Y) + f_代码构建_销毁数组(新变量_Z));
		}
		return "";
	}
	else {
		if (创建数组) {
			释放 += f_代码构建_销毁数组(新变量_X);
			释放 += f_代码构建_销毁数组(新变量_Y);
			释放 += f_代码构建_销毁数组(新变量_Z);
		}
	}

	return m_Code;
}

void C_分离XYZ节点::f_getStr(std::vector<std::vector<std::u16string>>& 文本) {
	auto* socket1 = f_get输出插座(1);
	auto* socket2 = f_get输出插座(2);
	auto* socket3 = f_get输出插座(3);

	switch (socket1->m_Type) {
	case E_值类型::e_Type_Vec3: {
		std::vector<std::u16string> 输入(5);
		输入[0] = f_getWName();

		输入[2] = u"x:" + f_浮点数值转宽字符串(DEF_F32插座数据(socket1));
		输入[3] = u"y:" + f_浮点数值转宽字符串(DEF_F32插座数据(socket2));
		输入[4] = u"z:" + f_浮点数值转宽字符串(DEF_F32插座数据(socket3));

		文本.push_back(输入);
		break;
	}
	case E_值类型::e_Type_Vec3_1D: {
		break;
	}
	}
}

C_节点基类* f_node_创建分离XYZ节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_分离XYZ节点(ctx);
}

C_节点基类* f_node_加载分离XYZ节点(S_设备环境& ctx, FILE* f) {
	C_分离XYZ节点* node = new C_分离XYZ节点(ctx);
	return node;
}

void f_node_保存分离XYZ节点(C_节点基类* n, FILE* f) {
	C_分离XYZ节点* node = dynamic_cast<C_分离XYZ节点*>(n);
}




C_混合节点::C_混合节点(S_设备环境& ctx) : C_节点基类(DEF_混合计算节点) {
	f_setWName(u"混合");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建Vec3插座_I(u"a", nullptr);
	DEF_创建Vec3插座_I(u"b", nullptr);
	DEF_创建F32插座_I(u"c", nullptr);

	DEF_创建Vec3插座_O(u"o", nullptr);


	f_构建代码_构建GPU插座变量(*f_get输入插座(1));
	f_构建代码_构建GPU插座变量(*f_get输入插座(2));
	f_构建代码_构建GPU插座变量(*f_get输入插座(3));
}

C_混合节点::~C_混合节点() {
	
}

bool C_混合节点::f_切换插座() {
	bool 创建数组 = false;

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	if (socket1->f_isLink()) {
		f_su_插座类型切换到连入的插座类型(this, e_插座Type_输入, 1, E_值类型::e_Type_Vec3);
		socket1 = f_get输入插座(1);
		f_su_切换后端插座类型(this, e_插座Type_输入, 2, socket1->m_Type);
		socket2 = f_get输入插座(2);
	}
	else if (socket2->f_isLink()) {
		f_su_插座类型切换到连入的插座类型(this, e_插座Type_输入, 2, E_值类型::e_Type_Vec3);
		socket2 = f_get输入插座(2);
		f_su_切换后端插座类型(this, e_插座Type_输入, 1, socket2->m_Type);
		socket1 = f_get输入插座(1);
	}
	f_su_切换后端插座类型(this, e_插座Type_输出, 1, socket1->m_Type);



	return 创建数组;
}

bool C_混合节点::f_update() {
	bool 创建数组 = f_切换插座();

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	if (f_代码构建_矢量类型(socket1->m_Type)) {
		if (f_代码构建_是否为矢量数组浮点(socket1->m_Type)) {
			创建数组 = true;
		}
		else {
			创建数组 = false;
		}
	}
	else {
		if (f_代码构建_是否为单值数组浮点(socket1->m_Type)) {
			创建数组 = true;
		}
		else {
			创建数组 = false;
		}
	}

	if (创建数组) {
		f_su_切换后端插座类型(this, e_插座Type_输入, 3, E_值类型::e_Type_F32_1D);
	}
	else {
		f_su_切换后端插座类型(this, e_插座Type_输入, 3, E_值类型::e_Type_F32);
	}
	auto* socket3 = f_get输入插座(3);

	auto* outSocket1 = f_get输出插座(1);



	if (f_代码构建_矢量类型(socket1->m_Type)) {
		if (f_代码构建_是否为矢量数组浮点(socket1->m_Type)) {
			auto* 结果 = DEF_Vec3插座_1D数据(outSocket1);

			f_JIT_Fn_矢量混合m(DEF_Vec3插座_1D数据(socket1), DEF_Vec3插座_1D数据(socket2), DEF_F32插座_1D数据(socket3), 结果);
		}
		else {
			DEF_Vec3插座数据(outSocket1) = mix(DEF_Vec3插座数据(socket1), DEF_Vec3插座数据(socket2), DEF_F32插座数据(socket3));
		}
	}
	else {
		if (f_代码构建_是否为单值数组浮点(socket1->m_Type)) {
			auto* 结果 = DEF_F32插座_1D数据(outSocket1);

			f_JIT_Fn_混合m(DEF_F32插座_1D数据(socket1), DEF_F32插座_1D数据(socket2), DEF_F32插座_1D数据(socket3), 结果);
		}
		else {
			DEF_F32插座数据(outSocket1) = mix(DEF_F32插座数据(socket1), DEF_F32插座数据(socket2), DEF_F32插座数据(socket3));
		}
	}

	return false;
}

std::string C_混合节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";

	auto* rt = f_getThis节点树();
	auto name = f_getName();



	bool 创建数组 = f_切换插座();
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	if (f_代码构建_矢量类型(socket1->m_Type)) {
		if (f_代码构建_是否为矢量数组浮点(socket1->m_Type)) {
			m_Code += DEF_S(S_Vec3Array*)" " + name + ";\n";
			创建数组 = true;
		}
		else {
			m_Code += DEF_S(vec3)" " + name + ";\n";
			创建数组 = false;
		}
	}
	else {
		if (f_代码构建_是否为单值数组浮点(socket1->m_Type)) {
			m_Code += DEF_S(S_F32Array*)" " + name + ";\n";
			创建数组 = true;
		}
		else {
			m_Code += DEF_S(float32)" " + name + ";\n";
			创建数组 = false;
		}
	}

	if (创建数组) {
		f_su_切换后端插座类型(this, e_插座Type_输入, 3, E_值类型::e_Type_F32_1D);
	}
	else {
		f_su_切换后端插座类型(this, e_插座Type_输入, 3, E_值类型::e_Type_F32);
	}

	auto* socket3 = f_get输入插座(3);



	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);
	m_Code += socket3->f_构建变量代码(0);

	if (rt->m_树类型 == E_节点树类型::e_type_着色节点树) {
		m_Code += name + " = ";
		m_Code += DEF_S(mix)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + socket3->f_getCode(0) + ");\n";

		if (f_代码构建_矢量类型(socket1->m_Type)) {
			if (socket1->m_GPU缓存.m_Buf) {
				f_buf_Vec3_at(socket1->m_GPU缓存) = DEF_Vec3插座数据(socket1);
			}
			if (socket2->m_GPU缓存.m_Buf) {
				f_buf_Vec3_at(socket2->m_GPU缓存) = DEF_Vec3插座数据(socket2);
			}
			
		}
		else {
			if (socket1->m_GPU缓存.m_Buf) {
				f_buf_F32_at(socket1->m_GPU缓存) = DEF_F32插座数据(socket1);
			}
			if (socket2->m_GPU缓存.m_Buf) {
				f_buf_F32_at(socket2->m_GPU缓存) = DEF_F32插座数据(socket2);
			}
		}
		if (socket3->m_GPU缓存.m_Buf) {
			f_buf_F32_at(socket3->m_GPU缓存) = DEF_F32插座数据(socket3);
		}
	}
	else {
		if (f_代码构建_矢量类型(socket1->m_Type)) {
			if (f_代码构建_是否为矢量数组浮点(socket1->m_Type)) {
				m_Code += name + " = " + f_代码构建_创建数组(E_值类型::e_Type_Vec3_1D, 1);

				m_Code += DEF_S(f_JIT_Fn_矢量混合m)"(";
				m_Code += socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + socket3->f_getCode(0) + ", " + name + ");\n";
			}
			else {
				m_Code += name + " = ";
				m_Code += DEF_S(mix)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", clamp(" + socket3->f_getCode(0) + ",0,1));\n";
			}
		}
		else {
			if (f_代码构建_是否为单值数组浮点(socket1->m_Type)) {
				m_Code += name + " = " + f_代码构建_创建数组(E_值类型::e_Type_F32_1D, 1);

				m_Code += DEF_S(f_JIT_Fn_混合m)"(" ;
				m_Code += socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + socket3->f_getCode(0) + ");\n";
			}
			else {
				m_Code += name + " = ";
				m_Code += DEF_S(mix)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", clamp(" + socket3->f_getCode(0) + ",0,1));\n";
			}
		}
	}
	m_Code += "}\n";


	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	else {
		if (创建数组) {
			释放 += f_代码构建_销毁数组(name);
		}
	}
	return m_Code;
}

void C_混合节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		//下一次读取数据指针 = f_prop_Load(m_是否改变原数据, 下一次读取数据指针);
	}

	free(文件块.m_data);
}

void C_混合节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	//f_prop_Save(m_是否改变原数据, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建混合节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_混合节点(ctx);
}

C_节点基类* f_node_加载混合节点(S_设备环境& ctx, FILE* f) {
	C_混合节点* node = new C_混合节点(ctx);
	return node;
}

void f_node_保存混合节点(C_节点基类* n, FILE* f) {
	C_混合节点* node = dynamic_cast<C_混合节点*>(n);
}




C_设置矢量分量节点::C_设置矢量分量节点(S_设备环境& ctx) : C_节点基类(DEF_设置矢量分量节点) {
	f_setWName(u"设置分量");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建Vec3插座_I(u"矢量", nullptr);
	DEF_创建F32插座_I(u"分量值", nullptr);
	DEF_创建I8插座_I(u"分量索引", nullptr);

	DEF_创建Vec3插座_O(u"矢量", nullptr);

	m_是否改变原数据 = f_alloc_BoolProp(nullptr, u"改变原数据");
	m_是否改变原数据.m_私有 = true;
	f_prop_Bool(m_是否改变原数据) = false;

}

C_设置矢量分量节点::~C_设置矢量分量节点() {
	f_prop_Release(m_是否改变原数据);
}

bool C_设置矢量分量节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	auto* socket3 = f_get输入插座(3);

	bool 创建数组 = false;
	if (f_代码构建_是否为数组(socket1->f_get接入的数据类型())) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_F32_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);

		创建数组 = true;
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_F32);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);
	}
	socket1 = f_get输入插座(1);
	socket2 = f_get输入插座(2);
	socket3 = f_get输入插座(3);


	if (创建数组) {
		auto* outData = DEF_Vec3插座_1D数据(f_get输出插座(1));
		f_JIT_Fn_设置矢量分量m(DEF_Vec3插座_1D数据(socket1), DEF_F32插座_1D数据(socket2), DEF_I8插座数据(socket3), outData);
	}
	else {
		vec3 v = f_JIT_Fn_设置矢量分量(DEF_Vec3插座数据(socket1), DEF_F32插座数据(socket2), DEF_I8插座数据(socket3));
		f_get输出插座(1)->f_setData(&v);
	}

	return false;
}

std::string C_设置矢量分量节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";


	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	auto* socket3 = f_get输入插座(3);

	bool 创建数组 = false;
	创建数组 |= socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D;
	创建数组 |= socket2->f_get接入的数据类型() == E_值类型::e_Type_F32_1D;
	//创建数组 |= socket3->f_get接入的数据类型() == E_值类型::e_Type_I8_1D;
	if (!socket1->f_isLink() && !socket1->f_isLink()) {
		创建数组 = false;
	}

	auto name = f_getName();
	if (创建数组) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_F32_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);
		m_Code += DEF_S(S_Vec3Array*)" " + name + ";\n";
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_F32);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);
		m_Code += DEF_S(vec3)" " + name + ";\n";
	}
	socket1 = f_get输入插座(1);
	socket2 = f_get输入插座(2);
	socket3 = f_get输入插座(3);


	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);
	m_Code += socket3->f_构建变量代码(0);


	
	if (f_prop_Bool(m_是否改变原数据)) {
		name = socket1->f_getCode(0);

		if (创建数组) {
			
		}
		else {
			
		}
	}
	else {
		if (创建数组) {
			m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "0") + ";\n";
			m_Code += DEF_S(f_JIT_Fn_设置矢量分量m)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + socket3->f_getCode(0) + ", " + name + ");\n";
		}
		else {
			m_Code += name + " = ";
			m_Code += DEF_S(f_JIT_Fn_设置矢量分量)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + socket3->f_getCode(0) + ");\n";
		}
	}
	m_Code += m_ReleaseCode;
	m_Code += "}\n";


	f_get输出插座(1)->f_setCode(name);

	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_设置矢量分量节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		下一次读取数据指针 = f_prop_Load(m_是否改变原数据, 下一次读取数据指针);
	}

	free(文件块.m_data);
}

void C_设置矢量分量节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	f_prop_Save(m_是否改变原数据, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建矢量分量节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_设置矢量分量节点(ctx);
}

C_节点基类* f_node_加载矢量分量节点(S_设备环境& ctx, FILE* f) {
	C_设置矢量分量节点* node = new C_设置矢量分量节点(ctx);
	return node;
}

void f_node_保存矢量分量节点(C_节点基类* n, FILE* f) {
	C_设置矢量分量节点* node = dynamic_cast<C_设置矢量分量节点*>(n);
}





C_取矢量分量节点::C_取矢量分量节点(S_设备环境& ctx) : C_节点基类(DEF_取矢量分量节点) {
	f_setWName(u"取矢量分量");
	m_Ctx = ctx;

	C_插座基类* socket;
	DEF_创建Vec3_1D插座_I(u"矢量", nullptr);
	DEF_创建I8_1D插座_I(u"索引", nullptr);

	DEF_创建F32_1D插座_O(u"分量", nullptr);
	

	m_分量类型 = f_alloc_EnumProp(nullptr, {
		{u"分量", u""},
		{u"最大", u""},
		{u"最小", u""},
	}, u"改变原数据");
	m_分量类型.m_私有 = true;
	

}

C_取矢量分量节点::~C_取矢量分量节点() {
	f_prop_Release(m_分量类型);
}

bool C_取矢量分量节点::f_update() {
	auto* 矢量 = DEF_Vec3插座_1D数据(f_get输入插座(1));
	auto* 索引 = DEF_I8插座_1D数据(f_get输入插座(2));
	auto* 分量 = DEF_F32插座_1D数据(f_get输出插座(1));

	f_vec_取矢量分量(矢量, 索引, 分量, m_分量类型);

	return false;
}

std::string C_取矢量分量节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";
	auto name = f_getName();

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	
	
	m_Code += DEF_S(S_F32Array*)" " + name + ";\n";


	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);

	m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_F32_1D, "0");
	m_Code += DEF_S(f_vec_取矢量分量)"(" + socket1->f_getCode(0) + "," + socket2->f_getCode(0) + "," + name + ", *(S_Props*)" + DEF_指针转字符串(&m_分量类型) + ");\n";

	m_Code += m_ReleaseCode;
	m_Code += "}\n";


	f_get输出插座(1)->f_setCode(name);

	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		return "";
	}
	释放 += f_代码构建_销毁数组(name);
	return m_Code;
}

void C_取矢量分量节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);

	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		下一次读取数据指针 = f_prop_Load(m_分量类型, 下一次读取数据指针);
	}

	free(文件块.m_data);
}

void C_取矢量分量节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	f_prop_Save(m_分量类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建取矢量分量节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_取矢量分量节点(ctx);
}

C_节点基类* f_node_加载取矢量分量节点(S_设备环境& ctx, FILE* f) {
	C_取矢量分量节点* node = new C_取矢量分量节点(ctx);
	return node;
}

void f_node_保存取矢量分量节点(C_节点基类* n, FILE* f) {
	C_取矢量分量节点* node = dynamic_cast<C_取矢量分量节点*>(n);
}




C_四元数计算节点::C_四元数计算节点(S_设备环境& ctx) : C_节点基类(DEF_四元数计算节点) {
	m_Ctx = ctx;
	f_setWName(u"四元数计算");


	C_插座基类* socket;
	DEF_创建Vec4插座_I(u"四元数A");
	DEF_创建Vec4插座_I(u"四元数B");
	
	DEF_创建Vec4插座_O(u"out");

	DEF_Vec4插座数据(f_get输入插座(1), 0) = { 0,0,0,1 };
	DEF_Vec4插座数据(f_get输入插座(2), 0) = { 0,0,0,1 };


	m_计算方式 = f_alloc_EnumProp(nullptr,
		//	0			1			2	
		{ 
			{u"*", u""}, {u"!", u""}, 
		},
		u"计算方式",
		0,
		nullptr
	);
	m_计算方式.m_私有 = true;

}

C_四元数计算节点::~C_四元数计算节点() {
	f_prop_Release(m_计算方式);
}

#define _DEF_四元数计算节点_插座类型转换_                                                                                           \
if (socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec4_1D || socket2->f_get接入的数据类型() == E_值类型::e_Type_Vec4_1D) {     \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec4_1D);                                          \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec4_1D);                                          \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec4_1D);                                          \
    创建数组 = true;                                                                                                                \
}                                                                                                                                   \
else {                                                                                                                              \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec4);                                             \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec4);                                             \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec4);                                             \
	创建数组 = false;                                                                                                               \
}                                                                                                                                   \
socket1 = f_get输入插座(1);                                                                                                         \
socket2 = f_get输入插座(2);                                                                                                          

bool C_四元数计算节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	bool 创建数组 = false;
	_DEF_四元数计算节点_插座类型转换_;


	if (创建数组) {

	}
	else {
		auto& 数据0 = DEF_Vec4插座数据(f_get输入插座(1), 0);
		auto& 数据1 = DEF_Vec4插座数据(f_get输入插座(2), 0);
		auto& q = DEF_Vec4插座数据(f_get输出插座(1), 0);

		q = f_graph_quat相乘(数据0, 数据1);
	}
	

	return false;
}

std::string C_四元数计算节点::f_编译(C_节点基类* rn, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放) {
	m_Code = "";
	m_ReleaseCode = "";

	std::string name = f_getName();
	
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	bool 创建数组 = false;
	_DEF_四元数计算节点_插座类型转换_;

	if (创建数组) {
		m_Code = DEF_S(S_Vec4Array);
		m_Code += "* " + name + ";\n";
	}
	else {
		m_Code = "vec4 " + name + ";\n";
	}
	
	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);
	if (创建数组) {
		m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec4_1D, f_代码构建_Array数组数量(socket1->f_getCode(0)));
		m_Code += DEF_S(f_math_quat相乘m);
		m_Code += "(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + name +");\n";
	}
	else {
		m_Code += name + " = " + DEF_S(f_graph_quat相乘) + "(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ");\n";
	}
	
	m_Code += m_ReleaseCode;
	m_Code += "}\n";


	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_四元数计算节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_计算方式, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_四元数计算节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算方式, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建四元数计算节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_四元数计算节点(ctx);
}

C_节点基类* f_node_加载四元数计算节点(S_设备环境& ctx, FILE* f) {
	C_四元数计算节点* node = new C_四元数计算节点(ctx);
	return node;
}

void f_node_保存四元数计算节点(C_节点基类* n, FILE* f) {
	C_四元数计算节点* node = dynamic_cast<C_四元数计算节点*>(n);
}









C_四元数变换节点::C_四元数变换节点(S_设备环境& ctx) : C_节点基类(DEF_四元变换节点) {
	m_Ctx = ctx;
	f_setWName(u"四元变换");


	C_插座基类* socket;
	DEF_创建Vec3插座_I(u"坐标数据", nullptr);
	DEF_创建Vec4插座_I(u"四元数");

	DEF_创建Vec3插座_O(u"out");

	m_计算方式 = f_alloc_EnumProp(nullptr, {
	    {u"正向"},
		{u"反向"},
		{u"正向叠加"},
		{u"反向叠加"},
	}, u"转换类型");
	m_计算方式.m_私有 = true;
}

C_四元数变换节点::~C_四元数变换节点() {
	f_prop_Release(m_计算方式);
}

bool C_四元数变换节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	bool 创建数组 = false;
	if (socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D || socket2->f_get接入的数据类型() == E_值类型::e_Type_Vec4_1D) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec4_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);
		创建数组 = true;
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec4);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);
	}

	if (创建数组) {
		const auto* 坐标 = DEF_Vec3插座_1D数据(f_get输入插座(1));
		const auto* 四元数 = DEF_Vec4插座_1D数据(f_get输入插座(2), 0);
		auto* out = DEF_Vec3插座_1D数据(f_get输出插座(1));

		f_math_quat变换m(坐标, 四元数, out, f_prop_enum(m_计算方式));
	}
	else {
		const auto& 坐标 = DEF_Vec3插座数据(f_get输入插座(1));
		const auto& 四元数 = DEF_Vec4插座数据(f_get输入插座(2), 0);
		auto& out = DEF_Vec3插座数据(f_get输出插座(1));

		switch (f_prop_enum(m_计算方式)) {
			case 0: {
				out = f_graph_quatTranform(四元数, 坐标);
				break;
			}
			case 1: {
				out = f_graph_quatTranformInv(四元数, 坐标);
				break;
			}
		}
	}
	return false;
}

std::string C_四元数变换节点::f_编译(C_节点基类* rn, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放) {
	m_ReleaseCode = "";
	m_Code = "";
	std::string name = f_getName();

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	bool 创建数组 = false;

	if (socket1->f_get接入的数据类型() == E_值类型::e_Type_Array || socket2->f_get接入的数据类型() == E_值类型::e_Type_Array) {
		创建数组 = true;
	}
	if (socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D || socket2->f_get接入的数据类型() == E_值类型::e_Type_Vec4_1D || 创建数组) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec4_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);
		创建数组 = true;

		m_Code = "S_Vec3Array* " + name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "1") + ";\n";
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec4);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);

		m_Code = "vec3 " + name + " = {};\n";
	}
	socket1 = f_get输入插座(1);
	socket2 = f_get输入插座(2);

	

	m_Code += "{\n";

	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);
	auto 计算方式 = f_代码构建_属性变量(m_计算方式, f_getThis节点树());

	if (创建数组) {
		m_Code += DEF_S(f_math_quat变换m);
		m_Code += "(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + name + ", " + 计算方式 + ");\n";
	}
	else {
		m_Code += "if(" + 计算方式 + "){\n";
		m_Code += name + " = " + DEF_S(f_graph_quatTranform)"(" + socket2->f_getCode(0) + ", " + socket1->f_getCode(0) + ");\n";
		m_Code += "} else {\n";
		m_Code += name + " = " + DEF_S(f_graph_quatTranformInv)"(" + socket2->f_getCode(0) + ", " + socket1->f_getCode(0) + ");\n";
		m_Code += "}\n";
	}

	m_Code += m_ReleaseCode;
	m_Code += "}\n";

	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		(*m_区域父节点).m_Code += m_Code;
		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_四元数变换节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_3, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_计算方式, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_四元数变换节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算方式, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建四元数变换节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_四元数变换节点(ctx);
}

C_节点基类* f_node_加载四元数变换节点(S_设备环境& ctx, FILE* f) {
	C_四元数变换节点* node = new C_四元数变换节点(ctx);
	return node;
}

void f_node_保存四元数变换节点(C_节点基类* n, FILE* f) {
	C_四元数变换节点* node = dynamic_cast<C_四元数变换节点*>(n);
}




C_向量角度组成四元数节点::C_向量角度组成四元数节点(S_设备环境& ctx) : C_节点基类(DEF_向量角度组成四元数节点) {
	m_Ctx = ctx;
	f_setWName(u"向量角度组成四元数");

	C_插座基类* socket;
	DEF_创建Vec3插座_I(u"向量", nullptr);
	DEF_创建F32插座_I(u"弧度", nullptr);
	DEF_创建Vec4插座_O(u"四元数", nullptr);

}

C_向量角度组成四元数节点::~C_向量角度组成四元数节点() {
}

#define _DEF_向量角度组成四元数节点_插座类型转换_                                                                                    \
bool 创建数组 = socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D ||                                                        \
                 socket2->f_get接入的数据类型() == E_值类型::e_Type_F32_1D;                                                          \
if (!创建数组 || (!socket1->f_isLink() && !socket2->f_isLink()) ) {                                                                  \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);                                              \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_F32);                                               \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec4);                                              \
	创建数组 = false;                                                                                                                \
}                                                                                                                                    \
else {                                                                                                                               \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);                                           \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_F32_1D);                                            \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec4_1D);                                           \
	创建数组 = true;                                                                                                                 \
}                                                                                                                                    \
socket1 = f_get输入插座(1);                                                                                                          \
socket2 = f_get输入插座(2);  

bool C_向量角度组成四元数节点::f_update() {
	
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	_DEF_向量角度组成四元数节点_插座类型转换_;

	if (创建数组) {
		const auto* 向量 = DEF_Vec3插座_1D数据(f_get输入插座(1), 0);
		const auto* 角度 = DEF_F32插座_1D数据(f_get输入插座(2), 0);
		auto* 四元数 = DEF_Vec4插座_1D数据(f_get输出插座(1), 0);
		f_math_quat以轴向和角度构建m(四元数, 向量, 角度);
	}
	else {
		const auto& 向量 = DEF_Vec3插座数据(f_get输入插座(1), 0);
		const auto& 角度 = DEF_F32插座数据(f_get输入插座(2), 0);
		auto& 四元数 = DEF_Vec4插座数据(f_get输出插座(1), 0);
		四元数 = f_graph_从轴向角度计算四元数(向量, M_角度转弧度(角度));
	}
	
	return false;
}

std::string C_向量角度组成四元数节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	_DEF_向量角度组成四元数节点_插座类型转换_;

	
	if (创建数组) {
		m_Code += DEF_S(S_Vec4Array*);
	}
	else {
		m_Code += DEF_S(vec4);
	}
	m_Code += " " + name + ";\n";

	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);

	if (创建数组) {
		m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec4_1D, "1") + ";\n";
		m_Code += DEF_S(f_math_quat以轴向和角度构建m);
		m_Code += "(" + name + ", " + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ");\n";
	}
	else {
		m_Code += name + " = ";
		m_Code += DEF_S(f_graph_从轴向角度计算四元数);
		m_Code += "(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ");\n";
	}
	m_Code += m_ReleaseCode;
	m_Code += "}\n";

	f_get输出插座(1)->f_setCode(name);

	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_向量角度组成四元数节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	auto 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;
		//f_prop_Load(m_反向, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_向量角度组成四元数节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);

	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));
	//f_prop_Save(m_反向, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建向量角度组成四元数节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_向量角度组成四元数节点(ctx);
}

C_节点基类* f_node_加载向量角度组成四元数节点(S_设备环境& ctx, FILE* f) {
	C_向量角度组成四元数节点* node = new C_向量角度组成四元数节点(ctx);
	return node;
}

void f_node_保存向量角度组成四元数节点(C_节点基类* n, FILE* f) {
	C_向量角度组成四元数节点* node = dynamic_cast<C_向量角度组成四元数节点*>(n);
}



C_四元数转换为欧拉角节点::C_四元数转换为欧拉角节点(S_设备环境& ctx) : C_节点基类(DEF_四元数转换为欧拉角节点) {
	m_Ctx = ctx;
	f_setWName(u"四元数转欧拉角");

	C_插座基类* socket;
	DEF_创建Vec4插座_I(u"四元数", nullptr);
	DEF_创建Vec3插座_O(u"欧拉角", nullptr);

	m_转换类型 = f_alloc_EnumProp(nullptr, {{u"欧拉角"}, {u"3X3矩阵"}, {u"4X4矩阵"}}, u"转换类型");
	m_转换类型.m_私有 = true;
	f_prop_enum(m_转换类型) = 0;

}

C_四元数转换为欧拉角节点::~C_四元数转换为欧拉角节点() {
}

bool C_四元数转换为欧拉角节点::f_update() {
	bool 创建数组 = false;
	auto* socket1 = f_get输入插座(1);
	if (socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec4_1D) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec4_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);
		创建数组 = true;
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec4);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);
		创建数组 = false;
	}
	socket1 = f_get输入插座(1);


	if (创建数组) {
		const auto* 四元数 = DEF_Vec4插座_1D数据(f_get输入插座(1));
		auto* 旋转角 = DEF_Vec3插座_1D数据(f_get输出插座(1));
		f_core_array_resize((S_Array*)旋转角, 四元数->count);

		for (uint32 i = 0; i < 四元数->count; ++i) {
			旋转角->ptr_userData[i] = f_graph_四元数转欧拉角(四元数->ptr_userData[i]);
		}
	}
	else {
		const vec4 四元数 = DEF_Vec4插座数据(f_get输入插座(1));
		DEF_Vec3插座数据(f_get输出插座(1)) = f_graph_四元数转欧拉角(四元数);
	}
	
	return false;
}

std::string C_四元数转换为欧拉角节点::DEF_节点编译函数{
	m_Code = "";
    m_ReleaseCode = "";

	bool 创建数组 = false;
	std::string name = f_getName();
	auto* rt = f_getThis节点树();

	
	auto* socket1 = f_get输入插座(1);
	if (socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec4_1D) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec4_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);
		创建数组 = true;
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec4);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);
		创建数组 = false;
	}
	socket1 = f_get输入插座(1);

	if (创建数组) {
		m_Code = DEF_S(S_Vec3Array)"* " + name + ";\n";
	}
	else {
		m_Code = "vec3 " + name + ";\n";
	}
	
	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);

	if (创建数组) {
		m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, f_代码构建_Array数组数量(socket1->f_getCode(0))) + ";\n";
		m_Code += DEF_S(f_math_四元数转欧拉角m);
		m_Code += "(" + socket1->f_getCode(0) + ", " + name + ");\n";
	}
	else {
		m_Code += name + " = " + DEF_S(f_graph_四元数转欧拉角) + "(" + socket1->f_getCode(0) + ");\n";
	}
	m_Code += m_ReleaseCode;
	m_Code += "}\n";

	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_四元数转换为欧拉角节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_转换类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_四元数转换为欧拉角节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_转换类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建四元数转换为欧拉角节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_四元数转换为欧拉角节点(ctx);
}

C_节点基类* f_node_加载四元数转换为欧拉角节点(S_设备环境& ctx, FILE* f) {
	C_四元数转换为欧拉角节点* node = new C_四元数转换为欧拉角节点(ctx);
	return node;
}

void f_node_保存四元数转换为欧拉角节点(C_节点基类* n, FILE* f) {
	C_四元数转换为欧拉角节点* node = dynamic_cast<C_四元数转换为欧拉角节点*>(n);
}





C_四元数转换为矩阵节点::C_四元数转换为矩阵节点(S_设备环境& ctx) : C_节点基类(DEF_四元数转换为4X4矩阵节点) {
	m_Ctx = ctx;
	f_setWName(u"四元数转矩阵");

	C_插座基类* socket;
	DEF_创建Vec4插座_I(u"四元数", nullptr);
	DEF_创建Mat4X4插座_O(u"矩阵", nullptr);

}

C_四元数转换为矩阵节点::~C_四元数转换为矩阵节点() {
}

bool C_四元数转换为矩阵节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	bool 创建数组 = false;
	if (socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec4_1D) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec4_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Mat4X4_1D);
		创建数组 = true;
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec4);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Mat4X4);
		创建数组 = false;
	}
	socket1 = f_get输入插座(1);

	if (创建数组) {
		auto& 四元数 = *DEF_Vec4插座_1D数据(socket1);
		auto* 矩阵 = DEF_Mat44插座_1D数据(f_get输出插座(1), 0);
		f_core_array_resize((S_Array*)矩阵, 四元数.count);

		for (uint32 i = 0; i < 四元数.count; ++i) {
			矩阵->ptr_userData[i] = f_mat4x4_quat(四元数.ptr_userData[i]);
		}
	}
	else {
		vec4 四元数 = DEF_Vec4插座数据(socket1);
		*DEF_Mat4X4插座数据(f_get输出插座(1), 0) = f_mat4x4_quat(四元数);
	}

	return false;
}

std::string C_四元数转换为矩阵节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";

	std::string name = f_getName();
	auto* rt = f_getThis节点树();

	bool 创建数组 = false;
	auto* socket1 = f_get输入插座(1);
	if (socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec4_1D) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec4_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Mat4X4_1D);
		创建数组 = true;
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec4);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Mat4X4);
		创建数组 = false;
	}
	socket1 = f_get输入插座(1);

	if (创建数组) {
		m_Code = DEF_S(S_Mat44Array);
		m_Code += "* " + name + ";\n";
	}
	else {
		m_Code = "Mat44f " + name + ";\n";
	}

	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);


	if (创建数组) {
		m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec4_1D, f_代码构建_Array数组数量(socket1->f_getCode(0)));
		m_Code += DEF_S(f_math_四元数转4X4矩阵m);
		m_Code += "(" + socket1->f_getCode(0) + ", " + name + ");\n";
	}
	else {
		m_Code += name + " = " + DEF_S(f_mat4x4_quat) + "(" + socket1->f_getCode(0) + ");\n";
	}

	m_Code += m_ReleaseCode;
	m_Code += "}\n";

	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

C_节点基类* f_node_创建四元数转换为矩阵节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_四元数转换为矩阵节点(ctx);
}

C_节点基类* f_node_加载四元数转换为矩阵节点(S_设备环境& ctx, FILE* f) {
	C_四元数转换为矩阵节点* node = new C_四元数转换为矩阵节点(ctx);
	return node;
}

void f_node_保存四元数转换为矩阵节点(C_节点基类* n, FILE* f) {
	C_四元数转换为矩阵节点* node = dynamic_cast<C_四元数转换为矩阵节点*>(n);
}




C_几何计算节点::C_几何计算节点(S_设备环境& ctx) : C_节点基类(DEF_几何计算节点) {
	m_Ctx = ctx;
	f_setWName(u"几何计算");

	C_插座基类* socket;
	DEF_创建Vec3插座_I(u"向量1", nullptr);
	DEF_创建Vec3插座_I(u"向量2", nullptr);
	DEF_创建Vec3插座_O(u"值", nullptr);

	m_计算类型 = f_alloc_EnumProp(nullptr,
		//	0			      1			      2			       3			4
		{
			{u"中心", u""}, //{u"叉积", ""}, {u"四元数", ""}, {u"角度", ""},
		},
		u"类型",
		0,
		nullptr
		);
	m_计算类型.m_私有 = true;

	f_构建代码_构建GPU插座变量(*f_get输入插座(1));
	f_构建代码_构建GPU插座变量(*f_get输入插座(2));
	f_构建代码_分配渲染器GPU属性变量(m_计算类型);
}

C_几何计算节点::~C_几何计算节点() {
	f_prop_Release(m_计算类型);
}

bool C_几何计算节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	auto& v1 = DEF_Vec3插座数据(socket1);
	auto& v2 = DEF_Vec3插座数据(socket2);

	vec4 quat = f_graph_quat两向量(normalize(v1), normalize(v2));
	vec3 rot = f_graph_四元数转欧拉角(quat);
	
	switch (f_prop_enum(m_计算类型)) {
	case 0: {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);
		DEF_F32插座数据(f_get输出插座(1)) = vec_dot(v1, v2);
		break;
	}
	case 1: {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);
		rot = vec_cross(v1, v2);
		f_get输出插座(1)->f_setData(&rot);
		break;
	}
	case 2: {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec4);
		break;
	}
	case 3: {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);
		auto a = M_弧度转角度(f_graph_两向量夹角弧度180(v1, v2));
		vec3 前进向量 = vec_cross(vec_cross(normalize(v2 - v1), v1), v1);
		float32 dt = vec_dot(前进向量, v1);
		DEF_F32插座数据(f_get输出插座(1)) = a;
		break;
	}
	}
	
	return false;
}

std::string C_几何计算节点::f_编译(C_节点基类* rn, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放) {
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();


	
	auto* rt = f_getThis节点树();
	if (rt->m_树类型 == E_节点树类型::e_type_着色节点树) {
		auto* socket1 = f_get输入插座(1);
		auto* socket2 = f_get输入插座(2);

		m_Code += socket1->f_构建变量代码(0);
		m_Code += socket2->f_构建变量代码(0);
		m_Code += "vec3 " + name + " = vec3(0);\n";

		m_Code += "switch(" + f_代码构建_属性变量(m_计算类型, rt) + "){\n";

		m_Code += "case 0:\n";
		//m_Code += name + " = dot(" + socket1->f_getCode() + ", " + socket2->f_getCode() + ");\n";
		m_Code += "break;\n";

		m_Code += "case 1:\n";
		m_Code += name + " = cross(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ");\n";
		m_Code += "break;\n";


		m_Code += "}\n";

		((int32*)m_计算类型.m_GPU缓存[0].m_Buf->m_mappedPtr)[m_计算类型.m_GPU缓存[0].m_Mem.m_偏移] = f_prop_enum(m_计算类型);
		//((int32*)m_计算类型.m_GPU缓存->m_mappedPtr)[m_计算类型.m_GPU内存偏移] = f_prop_enum(m_计算类型);

		if (socket1->m_GPU缓存.m_Buf) {
			f_buf_Vec3_at(socket1->m_GPU缓存) = DEF_Vec3插座数据(socket1);
			//((vec3*)socket1->m_GPU缓存->m_mappedPtr)[socket1->m_GPU内存偏移] = *DEF_Vec3插座数据(socket1, 0);
		}
		if (socket2->m_GPU缓存.m_Buf) {
			f_buf_Vec3_at(socket2->m_GPU缓存) = DEF_Vec3插座数据(socket2);
			//((vec3*)socket2->m_GPU缓存->m_mappedPtr)[socket2->m_GPU内存偏移] = *DEF_Vec3插座数据(socket2, 0);
		}
	}
	else {
		f_su_插座类型切换到连入的插座类型(this, E_插座方向::e_插座Type_输入, 1);
		auto* socket1 = f_get输入插座(1);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, socket1->m_Type);
		auto* socket2 = f_get输入插座(2);


		if (socket1->f_isLink() && socket2->f_isLink()) {
			
			bool 单值 = true;
			switch (socket1->m_Type) {
			case E_值类型::e_Type_Vec3: 
			case E_值类型::e_Type_Vec4: {
				switch (f_prop_enum(m_计算类型)) {
				case 0:
				case 1: {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);
					break;
				}
				case 2: {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec4);
					break;
				}
				case 3: {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);
					break;
				}
				}

				m_Code += "vec4 " + name + ";\n";
				break;
			}
			default:
				switch (f_prop_enum(m_计算类型)) {
				case 0:
				case 1: {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);
					m_Code += "S_Vec3Array* " + name + ";\n";
					break;
				}
				case 2: {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec4_1D);
					m_Code += "S_Vec4Array* " + name + ";\n";
					break;
				}
				case 3: {
					f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32_Array1D);
					m_Code += "S_F32Array* " + name + ";\n";
					break;
				}
				}

				单值 = false;
				break;
			}

			m_Code += "{\n";
			m_Code += socket1->f_构建变量代码(0);
			m_Code += socket2->f_构建变量代码(0);


			auto* rt = f_getThis节点树();
			m_Code += "switch(" + f_代码构建_属性变量(m_计算类型, rt) + "){\n";

			m_Code += "case 0 : {\n";

			m_Code += "}\n";
			m_Code += "case 1 : {\n";

			m_Code += "}\n";
			m_Code += "case 2 : {\n";
			{
				if (单值) {
					m_Code += name + " = f_math_quat两向量(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ");\n";
				}
				else {
					m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec4_1D, f_代码构建_Array数组数量(socket1->f_getCode(0)));
					m_Code += "f_math_quat两向量m(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + name + ");\n";
				}
			}

			m_Code += "}\n";
			m_Code += "case 3 : {\n";

			m_Code += "}\n";

			m_Code += "}\n";

			m_Code += "}\n";
			m_Code += m_ReleaseCode;
		}
	}
	
	f_get输出插座(1)->f_setCode(name);

	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		return "";
	}
	return m_Code;
}

void C_几何计算节点::f_getStr(std::vector<std::vector<std::u16string>>& 文本) {
	auto socket1 = f_get输出插座(1);

	std::vector<std::u16string> 输出(2);
	输出[0] = f_getWName();
	switch (f_prop_enum(m_计算类型)) {
	case 0: 
		输出[1] = u"点积";
		break;
	case 1: 
		输出[1] = u"叉积";
		break;
	case 2: 
		输出[1] = u"四元数";
		break;
	case 3: 
		输出[1] = u"旋转角度";
		break;
	}


	switch (socket1->m_Type) {
	case E_值类型::e_Type_Vec3_1D: {
		const auto& v1 = *DEF_Vec3插座_1D数据(socket1);
		
		for (uint32 i = 0; i < v1.count; ++i) {
			输出.push_back(u"x:" + f_浮点数值转宽字符串(v1.ptr_userData[i].x));
			输出.push_back(u"y:" + f_浮点数值转宽字符串(v1.ptr_userData[i].y));
			输出.push_back(u"z:" + f_浮点数值转宽字符串(v1.ptr_userData[i].z));
		}

		break;
	}
	case E_值类型::e_Type_Vec3: {
		const auto& v1 = DEF_Vec3插座数据(socket1);

		输出.push_back(u"x:" + f_浮点数值转宽字符串(v1.x));
		输出.push_back(u"y:" + f_浮点数值转宽字符串(v1.y));
		输出.push_back(u"z:" + f_浮点数值转宽字符串(v1.z));

		文本.push_back(输出);
		break;
	}
	case E_值类型::e_Type_F32: {
		const auto& v1 = DEF_F32插座数据(socket1);
		输出.push_back(f_浮点数值转宽字符串(v1));
		文本.push_back(输出);
		break;
	}
	}
}

void C_几何计算节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_prop_Load(m_计算类型, f);
}

void C_几何计算节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_prop_Save(m_计算类型, f);
}

C_节点基类* f_node_创建几何计算节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_几何计算节点(ctx);
}

C_节点基类* f_node_加载几何计算节点(S_设备环境& ctx, FILE* f) {
	C_几何计算节点* node = new C_几何计算节点(ctx);
	return node;
}

void f_node_保存几何计算节点(C_节点基类* n, FILE* f) {
	C_几何计算节点* node = dynamic_cast<C_几何计算节点*>(n);
}





C_矢量统计节点::C_矢量统计节点(S_设备环境& ctx) : C_节点基类(DEF_矢量统计节点) {
	m_Ctx = ctx;
	f_setWName(u"矢量统计");

	DEF_创建Vec3_1D插座_I(u"矢量");
	DEF_创建Vec3插座_O(u"矢量");

	m_计算类型 = f_alloc_EnumProp(nullptr, {
		{u"中心"}, 
		{u"边界中心"},
	}, u"计算类型");
	m_计算类型.m_私有 = true;
	f_prop_enum(m_计算类型) = 0;

}

C_矢量统计节点::~C_矢量统计节点() {
}

bool C_矢量统计节点::f_update() {
	bool 创建数组 = false;
	auto* socket1 = f_get输入插座(1);
	
	auto* 矢量 = DEF_Vec3插座_1D数据(socket1);

	vec3 中心={};
	for (uint32 i = 0; i < 矢量->count; ++i) {
		中心 += 矢量->ptr_userData[i];
	}
	中心 /= 矢量->count;

	f_get输出插座(1)->f_setData(&中心);

	return false;
}

std::string C_矢量统计节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";

	bool 创建数组 = false;
	std::string name = f_getName();
	auto* rt = f_getThis节点树();


	auto* socket1 = f_get输入插座(1);
	
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);
	创建数组 = false;
	socket1 = f_get输入插座(1);

	m_Code = "vec3 " + name + ";\n";

	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += name + " = " + DEF_S(f_mat_点统计v3) + "(" + socket1->f_getCode(0) + ", (S_Props*)" + DEF_指针转字符串(&m_计算类型) + ");\n";
	m_Code += m_ReleaseCode;
	m_Code += "}\n";

	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_矢量统计节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		if (f_file_版本对比(文件块, S_引擎配置::g_低版本号_0, S_引擎配置::g_文件版本号)) {
			下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
		}
	}
	free(文件块.m_data);
}

void C_矢量统计节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建矢量统计节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_矢量统计节点(ctx);
}

C_节点基类* f_node_加载矢量统计节点(S_设备环境& ctx, FILE* f) {
	C_矢量统计节点* node = new C_矢量统计节点(ctx);
	return node;
}

void f_node_保存矢量统计节点(C_节点基类* n, FILE* f) {
	C_矢量统计节点* node = dynamic_cast<C_矢量统计节点*>(n);
}





C_三角函数计算节点::C_三角函数计算节点(S_设备环境& ctx) : C_节点基类(DEF_三角函数节点) {
	m_Ctx = ctx;
	f_setWName(u"三角函数");

	C_插座基类* socket;
	DEF_创建F32插座_I(u"值", nullptr);
	DEF_创建F32插座_O(u"值", nullptr);


	m_计算类型 = f_alloc_EnumProp(nullptr, { {u"sin", u""}, {u"cos", u""}, {u"tan", u""}
								         , {u"asin", u""}, {u"acos", u""}, {u"atan", u""}
								         , {u"sinh", u""}, {u"cosh", u""}, {u"tanh", u""}
								         , {u"asinh", u""}, {u"acosh", u""}, {u"atanh", u""}
		}, u"三角函数");
	m_计算类型.m_私有 = true;
}

C_三角函数计算节点::~C_三角函数计算节点() {
	f_prop_Release(m_计算类型);
}

bool C_三角函数计算节点::f_update() {
	auto* socket = f_get输入插座(1);
	if (socket->f_isLink() && socket->f_get接入的数据类型() == E_值类型::e_Type_F32_1D) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_F32_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32_1D);
		socket = f_get输入插座(1);

		auto* inData1 = DEF_F32插座_1D数据(socket);
		auto* outData1 = DEF_F32插座_1D数据(f_get输出插座(1));
		f_core_array_resize((S_Array*)outData1, inData1->count);
		switch (f_prop_enum(m_计算类型)) {
		case 0: {
			for (uint32 i = 0; i < inData1->count; ++i) {
				outData1->ptr_userData[i] = sinf(inData1->ptr_userData[i]);
			}
			break;
		}
		case 1: {
			for (uint32 i = 0; i < inData1->count; ++i) {
				outData1->ptr_userData[i] = cosf(inData1->ptr_userData[i]);
			}
			break;
		}
		case 2: {
			for (uint32 i = 0; i < inData1->count; ++i) {
				outData1->ptr_userData[i] = tanf(inData1->ptr_userData[i]);
			}
			break;
		}

		case 3: {
			for (uint32 i = 0; i < inData1->count; ++i) {
				outData1->ptr_userData[i] = asinf(inData1->ptr_userData[i]);
			}
			break;
		}
		case 4: {
			for (uint32 i = 0; i < inData1->count; ++i) {
				outData1->ptr_userData[i] = acosf(inData1->ptr_userData[i]);
			}
			break;
		}
		case 5: {
			for (uint32 i = 0; i < inData1->count; ++i) {
				outData1->ptr_userData[i] = atanf(inData1->ptr_userData[i]);
			}
			break;
		}

		}
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_F32);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);
		socket = f_get输入插座(1);

		auto& inData1 = DEF_F32插座数据(socket);
		auto& outData1 = DEF_F32插座数据(f_get输出插座(1));
		switch (f_prop_enum(m_计算类型)) {
		case 0: {
			outData1 = sinf(inData1);
			break;
		}
		case 1: {
			outData1 = cosf(inData1);
			break;
		}
		case 2: {
			outData1 = tanf(inData1);
			break;
		}

		case 3: {
			outData1 = asinf(inData1);
			break;
		}
		case 4: {
			outData1 = acosf(inData1);
			break;
		}
		case 5: {
			outData1 = atanf(inData1);
			break;
		}

		}
	}
	
	
	return false;
}

std::string C_三角函数计算节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";
	auto* socket = f_get输入插座(1);
	

	bool 创建数组 = false;
	std::string name = f_getName();
	std::string 类型 = f_代码构建_属性变量(m_计算类型, f_getThis节点树());
	if (socket->f_isLink() && socket->f_get接入的数据类型() == E_值类型::e_Type_F32_1D) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_F32_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32_1D);

		创建数组 = true;
		m_Code += "S_F32Array* " + name + " = " + f_代码构建_创建Array(E_值类型::e_Type_F32_1D, "1");
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_F32);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);

		m_Code += "float32 " + name + " = 0;\n";
	}
	socket = f_get输入插座(1);


	m_Code += "{\n";
	m_Code += socket->f_构建变量代码(0);
	if (创建数组) {
		m_Code += DEF_S(f_JIT_Fn_三角函数s);
		m_Code += "(" + socket->f_getCode(0) + ", " + name + ", " + 类型 + ");\n";
	}
	else {
		m_Code += name + " = ";
		m_Code += DEF_S(f_JIT_Fn_三角函数);
		m_Code += "(" + socket->f_getCode(0) + ", " + 类型 + ");\n";
	}
	m_Code += m_ReleaseCode;
	m_Code += "}\n";
	
	f_get输出插座(1)->f_setCode(name);


	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}

		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_三角函数计算节点::f_getStr(std::vector<std::vector<std::u16string>>& 文本) {
	std::vector<std::u16string> 输入(1);
	输入[0] = f_getWName();

	auto* socket = f_get输入插座(1);
	if (socket->f_isLink() && socket->f_get接入的数据类型() == E_值类型::e_Type_F32_1D) {
		auto* inData1 = DEF_F32插座_1D数据(socket);
		auto* outData1 = DEF_F32插座_1D数据(f_get输出插座(1));

		for (uint32 i = 0; i < inData1->count; ++i) {
			输入.push_back(f_浮点数值转宽字符串(inData1->ptr_userData[i]));
		}
		文本.push_back(输入);

		输入.resize(1);
		输入[0] = f_getWName();
		for (uint32 i = 0; i < outData1->count; ++i) {
			输入.push_back(f_浮点数值转宽字符串(outData1->ptr_userData[i]));
		}
		文本.push_back(输入);

	}
	else {
		auto& inData1 = DEF_F32插座数据(socket);
		auto& outData1 = DEF_F32插座数据(f_get输出插座(1));

		输入.push_back(f_浮点数值转宽字符串(inData1));
		文本.push_back(输入);

		输入.resize(1);
		输入[0] = f_getWName();
		输入.push_back(f_浮点数值转宽字符串(outData1));
		文本.push_back(输入);
	}
}

void C_三角函数计算节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_三角函数计算节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建三角函数计算节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_三角函数计算节点(ctx);
}

C_节点基类* f_node_加载三角函数计算节点(S_设备环境& ctx, FILE* f) {
	C_三角函数计算节点* node = new C_三角函数计算节点(ctx);
	return node;
}

void f_node_保存三角函数计算节点(C_节点基类* n, FILE* f) {
	C_三角函数计算节点* node = dynamic_cast<C_三角函数计算节点*>(n);
}




C_向量归一化节点::C_向量归一化节点(S_设备环境& ctx) : C_节点基类(DEF_归一化节点) {
	m_Ctx = ctx;
	f_setWName(u"归一化");

	C_插座基类* socket;
	DEF_创建Vec3插座_I(u"vec3", nullptr);
	DEF_创建Vec3插座_O(u"vec3", nullptr);

	m_计算类型 = f_alloc_EnumProp(nullptr, {
		{u"归一化",	u""}, 
		{u"长度",	u""},
		{u"绝对值", u""},
	}, u"向量标量计算");
	m_计算类型.m_私有 = true;
}

C_向量归一化节点::~C_向量归一化节点() {
	f_prop_Release(m_计算类型);
}

bool C_向量归一化节点::f_update() {
	auto* socket = f_get输入插座(1);

	if (socket->f_isLink() && socket->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);

		auto* r = DEF_Vec3插座_1D数据(f_get输出插座(1));
		f_math_向量归一化m(DEF_Vec3插座_1D数据(f_get输入插座(1)), r, 0);
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);

		vec3 n = vec_normalize(DEF_Vec3插座数据(f_get输入插座(1)));
		f_get输出插座(1)->f_setData(&n);
	}
	
	return false;
}

std::string C_向量归一化节点::DEF_节点编译函数 {
	m_Code = "";
	m_ReleaseCode = "";
	auto* rt = f_getThis节点树();

	std::string name = f_getName();
	bool 创建数组 = false;


	auto* socket = f_get输入插座(1);
	
	
	if (rt->m_树类型 == E_节点树类型::e_type_着色节点树) {
		m_Code += socket->f_构建变量代码(0);
		switch (f_prop_enum(m_计算类型)) {
			case 0: {
				f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);
				m_Code += DEF_S(vec3)" " + name + " = " + DEF_S(normalize) + "(" + socket->f_getCode(0) + ");\n";
				break;
			}
			case 1: {
				f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);
				m_Code += DEF_S(float)" " + name + " = " + DEF_S(length) + "(" + socket->f_getCode(0) + ");\n";
				break;
			}
			case 2: {
				f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);
				m_Code += DEF_S(vec3)" " + name + " = " + DEF_S(abs) + "(" + socket->f_getCode(0) + ");\n";
				break;
			}
		}
		
	}
	else {
		if (socket->f_isLink() && socket->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D) {
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);

			创建数组 = true;
			m_Code += "S_Vec3Array* " + name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "1");
		}
		else {
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);

			m_Code += "vec3 " + name + " = {};\n";
		}
		socket = f_get输入插座(1);

		m_Code += "{\n";
		m_Code += socket->f_构建变量代码(0);
		if (创建数组) {
			m_Code += DEF_S(f_math_向量归一化m);
			m_Code += "(" + socket->f_getCode(0) + ", " + name + ", 0);\n";
		}
		else {
			m_Code += name + " = " + DEF_S(f_math_向量归一化) + "(" + socket->f_getCode(0) + ", 0);\n";
		}
		m_Code += m_ReleaseCode;
		m_Code += "}\n";
	}
	


	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_向量归一化节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	auto 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_向量归一化节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建向量归一化节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_向量归一化节点(ctx);
}

C_节点基类* f_node_加载向量归一化节点(S_设备环境& ctx, FILE* f) {
	C_向量归一化节点* node = new C_向量归一化节点(ctx);
	return node;
}

void f_node_保存向量归一化节点(C_节点基类* n, FILE* f) {
	C_向量归一化节点* node = dynamic_cast<C_向量归一化节点*>(n);
}




C_计算两向量点积量节点::C_计算两向量点积量节点(S_设备环境& ctx) : C_节点基类(DEF_两向量标量计算节点) {
	m_Ctx = ctx;
	f_setWName(u"点积");

	C_插座基类* socket;
	DEF_创建Vec3插座_I(u"vec3", nullptr);
	DEF_创建Vec3插座_I(u"vec3", nullptr);
	DEF_创建F32插座_O(u"点积", nullptr);

	m_计算类型 = f_alloc_EnumProp(nullptr, { 
		{u"点积",		u""},
		{u"角度",		u""},
		{u"叠加点积",	u""},
	}, u"向量标量计算");
	m_计算类型.m_私有 = true;


	f_构建代码_构建GPU插座变量(*f_get输入插座(1));
	f_构建代码_构建GPU插座变量(*f_get输入插座(2));
	f_构建代码_分配渲染器GPU属性变量(m_计算类型);
}

C_计算两向量点积量节点::~C_计算两向量点积量节点() {
	f_prop_Release(m_计算类型);
}

#define _DEF_计算两向量标量节点_插座类型转换_                                                     \
创建数组 = socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D ||                          \
                 socket2->f_get接入的数据类型() == E_值类型::e_Type_F32_1D;                       \
if (!创建数组 || (!socket1->f_isLink() && !socket2->f_isLink()) ) {                               \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);           \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec3);           \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);            \
	创建数组 = false;                                                                             \
}                                                                                                 \
else {                                                                                            \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);        \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec3_1D);        \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32_1D);         \
	创建数组 = true;                                                                              \
}                                                                                                 \
socket1 = f_get输入插座(1);                                                                       \
socket2 = f_get输入插座(2);  

bool C_计算两向量点积量节点::f_update() {
	return false;
}

std::string C_计算两向量点积量节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();
	bool 创建数组 = false;

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	auto* rt = f_getThis节点树();
	if (rt->m_树类型 == E_节点树类型::e_type_着色节点树) {
		m_Code += socket1->f_构建变量代码(0);
		m_Code += socket2->f_构建变量代码(0);

		m_Code += "float " + name + " = 0;\n";

		m_Code += "switch(" + f_代码构建_属性变量(m_计算类型, rt) + "){\n";

		m_Code += "case 0:\n";
		m_Code += name + " = dot(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ");\n";
		m_Code += "break;\n";

		m_Code += "case 1:\n";
		//m_Code += name + " = cross(" + socket1->f_getCode() + ", " + socket2->f_getCode() + ");\n";
		m_Code += "break;\n";

		m_Code += "}\n";

		((int32*)m_计算类型.m_GPU缓存[0].m_Buf->m_mappedPtr)[m_计算类型.m_GPU缓存[0].m_Mem.m_偏移] = f_prop_enum(m_计算类型);
		
		if (socket1->m_GPU缓存.m_Buf) {
			f_buf_Vec3_at(socket1->m_GPU缓存) = DEF_Vec3插座数据(socket1);
		}
		if (socket2->m_GPU缓存.m_Buf) {
			f_buf_Vec3_at(socket2->m_GPU缓存) = DEF_Vec3插座数据(socket2);
		}
	}
	else {
		_DEF_计算两向量标量节点_插座类型转换_;

		if (创建数组) {
			m_Code += DEF_S(S_F32Array*);
		}
		else {
			m_Code += DEF_S(float32);
		}
		m_Code += " " + name + ";\n";

		m_Code += "{\n";
		m_Code += socket1->f_构建变量代码(0);
		m_Code += socket2->f_构建变量代码(0);

		std::string 计算类型 = f_代码构建_属性变量(m_计算类型, f_getThis节点树());

		
		if (创建数组) {
			m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_F32_1D, "1") + ";\n";
			m_Code += DEF_S(f_math_两向量标量m);
			m_Code += "(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + name + ", " + 计算类型 + ");\n";
		}
		else {
			m_Code += name + " = f_math_两向量标量(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + 计算类型 + ");\n";
		}
		m_Code += m_ReleaseCode;
		m_Code += "}\n";
	}

	

	f_get输出插座(1)->f_setCode(name);

	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}

		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_计算两向量点积量节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_计算两向量点积量节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}


C_节点基类* f_node_创建计算标量节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_计算两向量点积量节点(ctx);
}

C_节点基类* f_node_加载计算标量节点(S_设备环境& ctx, FILE* f) {
	C_计算两向量点积量节点* node = new C_计算两向量点积量节点(ctx);
	return node;
}

void f_node_保存计算标量节点(C_节点基类* n, FILE* f) {
	C_计算两向量点积量节点* node = dynamic_cast<C_计算两向量点积量节点*>(n);
}




C_计算单向量标量节点::C_计算单向量标量节点(S_设备环境& ctx) : C_节点基类(DEF_向量标量计算节点) {
	m_Ctx = ctx;
	f_setWName(u"向量长度");

	C_插座基类* socket;
	DEF_创建Vec3插座_I(u"vec3", nullptr);

	DEF_创建F32插座_O(u"长度", nullptr);


	m_计算方式 = f_alloc_EnumProp(nullptr, {
		{u"长度",		u""},
		{u"亮度",		u""},
		{u"累加",		u""},
		{u"截取长度",	u""},
	}, u"向量标量计算");
	m_计算方式.m_私有 = true;

	f_构建代码_分配渲染器GPU属性变量(m_计算方式);
}

C_计算单向量标量节点::~C_计算单向量标量节点() {
	f_构建代码_释放渲染器GPU属性变量(m_计算方式);
}

bool C_计算单向量标量节点::f_update() {
	bool 创建数组 = false;

	auto* socket1 = f_get输入插座(1);
	
	if (socket1->f_isLink() && socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32_1D);

		创建数组 = true;
	}
	else {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);
	}
	socket1 = f_get输入插座(1);
	auto outSocket1 = f_get输出插座(1);

	if (创建数组) {
		switch (f_prop_enum(m_计算方式)) {
			case 0:
				f_math_向量长度m(DEF_F32插座_1D数据(outSocket1), DEF_Vec3插座_1D数据(socket1), 0);
				break;
			default:
				break;
		}
	}
	else {
		auto& v1 = DEF_Vec3插座数据(socket1);

		switch (f_prop_enum(m_计算方式)) {
			case 0:
				DEF_F32插座数据(f_get输出插座(2)) = vec_len(v1);
				break;
			case 1:
				DEF_F32插座数据(f_get输出插座(2)) = dot({ 0.2125, 0.7154, 0.0721 }, v1);
				break;
			default:
				break;
		}
	}
	
	return false;
}

std::string C_计算单向量标量节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";

	auto* socket1 = f_get输入插座(1);
	std::string name = f_getName();
	bool 创建数组 = false;



	auto* rt = f_getThis节点树();
	if (rt->m_树类型 == E_节点树类型::e_type_着色节点树) {
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);
		f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);
		socket1 = f_get输入插座(1);
		m_Code += socket1->f_构建变量代码(0);

		m_Code += "float " + name + " = 0;\n";
		m_Code += "{\n";
		m_Code += "switch(" + f_代码构建_属性变量(m_计算方式, rt) + "){\n";

		m_Code += "case 0:\n";
		m_Code += name + " = length(" + socket1->f_getCode(0) + ");\n";
		m_Code += "break;\n";

		m_Code += "case 1:\n";
		m_Code += name + " = dot(vec3(0.2125,0.7154,0.0721), " + socket1->f_getCode(0) + ");\n";
		m_Code += "break;\n";

		m_Code += "}\n";
		m_Code += "}\n";
	}
	else {
		
		if (socket1->f_isLink() && socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D) {
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32_1D);

			创建数组 = true;
			m_Code += "S_F32Array* " + name + ";\n";
		}
		else {
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);
			f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);

			m_Code += "float32 " + name + " = 0;\n";
		}
		socket1 = f_get输入插座(1);


		m_Code += "{\n";
		m_Code += socket1->f_构建变量代码(0);
		if (创建数组) {
			auto* rt = f_getThis节点树();
			m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_F32_1D, "1") + ";\n";
			m_Code += DEF_S(f_math_向量长度m)"(" + name + ", " + socket1->f_getCode(0) + ", " + f_代码构建_属性变量(m_计算方式, rt) + ");\n";
		}
		else {
			m_Code += name + " = " + DEF_S(vec3_len)"(" + socket1->f_getCode(0) + ");\n";
		}
		m_Code += m_ReleaseCode;
		m_Code += "}\n";
	}
	

	f_get输出插座(1)->f_setCode(name);


	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}

		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_计算单向量标量节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_计算方式, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_计算单向量标量节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);

	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算方式, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建单向量标量节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_计算单向量标量节点(ctx);
}

C_节点基类* f_node_加载单向量标量节点(S_设备环境& ctx, FILE* f) {
	C_计算单向量标量节点* node = new C_计算单向量标量节点(ctx);
	return node;
}

void f_node_保存单向量标量节点(C_节点基类* n, FILE* f) {
	C_计算单向量标量节点* node = dynamic_cast<C_计算单向量标量节点*>(n);
}




C_旋转向量节点::C_旋转向量节点(S_设备环境& ctx) : C_节点基类(DEF_旋转向量节点) {
	m_Ctx = ctx;
	f_setWName(u"旋转向量");

	C_插座基类* socket;
	DEF_创建Vec3插座_I(u"法线", nullptr);
	DEF_创建Vec2插座_I(u"UV", nullptr);
	DEF_创建Vec3插座_I(u"上方向", nullptr);
	
	DEF_Vec3插座数据(f_get输入插座(3)) = {1,0,0};

	DEF_创建Vec3插座_O(u"向量", nullptr);

	m_计算类型 = f_alloc_EnumProp(nullptr, {
		{u"独立",u""},
		{u"链接",u""},
		{u"螺旋",u""},
		{u"交叉",u""},
	}, u"相邻方式");
	m_计算类型.m_私有 = true;
}

C_旋转向量节点::~C_旋转向量节点() {
}

#define _DEF_旋转向量节点_插座类型转换_                                                                                             \
if (socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D || socket2->f_get接入的数据类型() == E_值类型::e_Type_Vec2_1D) {     \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);                                          \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec2_1D);                                          \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);                                          \
    创建数组 = true;                                                                                                                \
}                                                                                                                                   \
else {                                                                                                                              \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);                                             \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec2);                                             \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);                                             \
	创建数组 = false;                                                                                                               \
}                                                                                                                                   \
socket1 = f_get输入插座(1);                                                                                                         \
socket2 = f_get输入插座(2);                                                                                                          

bool C_旋转向量节点::f_update() {
	bool 创建数组 = false;

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	_DEF_旋转向量节点_插座类型转换_;

	auto outSocket1 = f_get输出插座(1);  
	if (创建数组) {
		const auto* 法线 = DEF_Vec3插座_1D数据(socket1, 0);
		const auto* UV = DEF_Vec2插座_1D数据(socket2, 0);
		
		auto* 向量 = DEF_Vec3插座_1D数据(outSocket1, 0);

		f_JIT_旋转向量节点(向量, 法线, UV, f_prop_enum(m_计算类型));
	}
	else {
		const vec3 法线 = DEF_Vec3插座数据(socket1);
		const vec2 UV = DEF_Vec2插座数据(socket2, 0);
		
		vec3& 向量 = DEF_Vec3插座数据(outSocket1);

		const vec3 TangentSample = f_SphereSampling(UV);
		向量 = f_SphereSampling_toWorld(TangentSample, 法线);
	}

	return false;
}

std::string C_旋转向量节点::DEF_节点编译函数 {
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();

	bool 创建数组 = false;

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);

	_DEF_旋转向量节点_插座类型转换_;

	if (创建数组) {
		m_Code += DEF_S(S_Vec3Array*);
	}
	else {
		m_Code += DEF_S(vec3);
	}
	m_Code += " " + name + ";\n";

	auto outSocket1 = f_get输出插座(1); 

	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);
	
	if (创建数组) {
		auto 元素相邻方式 = f_代码构建_属性变量(m_计算类型, f_getThis节点树());
		m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "1") + ";\n";
		m_Code += DEF_S(f_JIT_旋转向量节点);
		m_Code += "(" + name + ", " + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + 元素相邻方式 + ");\n";
	}
	else {
		m_Code += DEF_S(vec3 TangentSample );
		m_Code += " = " DEF_S(f_SphereSampling);
		m_Code += "(" + socket2->f_getCode(0) + ");\n";
		m_Code += name + " = ";
		m_Code += DEF_S(f_SphereSampling_toWorld);
		m_Code += "(TangentSample," + socket1->f_getCode(0) + ");\n";
	}
	
	m_Code += m_ReleaseCode;
	m_Code += "}\n";


	outSocket1->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_旋转向量节点::f_Copy(const C_节点基类* node) {
	auto* cpNode = dynamic_cast<const C_旋转向量节点*>(node);
	f_prop_enum(m_计算类型) = f_prop_enum(cpNode->m_计算类型);
}

void C_旋转向量节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	auto 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_旋转向量节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建旋转向量节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_旋转向量节点(ctx);
}

C_节点基类* f_node_加载旋转向量节点(S_设备环境& ctx, FILE* f) {
	C_旋转向量节点* node = new C_旋转向量节点(ctx);
	return node;
}

void f_node_保存旋转向量节点(C_节点基类* n, FILE* f) {
	C_旋转向量节点* node = dynamic_cast<C_旋转向量节点*>(n);
}




C_按轴向旋转向量节点::C_按轴向旋转向量节点(S_设备环境& ctx) : C_节点基类(DEF_按轴向旋转向量节点) {
	m_Ctx = ctx;
	f_setWName(u"轴向旋转向量");

	C_插座基类* socket;
	DEF_创建Vec3插座_I(u"向量", nullptr);
	DEF_创建Vec3插座_I(u"轴向", nullptr);
	DEF_创建F32插座_I(u"角度", nullptr);

	DEF_创建Vec3插座_O(u"向量", nullptr);


	m_计算类型 = f_alloc_EnumProp(nullptr, {
		{u"单一",u""},
		{u"累加",u""},
		}, u"旋转方式");
	m_计算类型.m_私有 = true;

}

C_按轴向旋转向量节点::~C_按轴向旋转向量节点() {
}

#define _DEF_轴向旋转向量节点_插座类型转换_                                                                                        \
if (socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D || socket2->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D       \
                                                               || socket3->f_get接入的数据类型() == E_值类型::e_Type_F32_1D) {     \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);                                         \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec3_1D);                                         \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 3, E_值类型::e_Type_F32_1D);                                          \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);                                         \
    创建数组 = true;                                                                                                               \
}                                                                                                                                  \
else {                                                                                                                             \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);                                            \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec3);                                            \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 3, E_值类型::e_Type_F32);                                             \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);                                            \
	创建数组 = false;                                                                                                              \
}                                                                                                                                  \
socket1 = f_get输入插座(1);                                                                                                        \
socket2 = f_get输入插座(2);                                                                                                        \
socket3 = f_get输入插座(3);                                                                                                          


bool C_按轴向旋转向量节点::f_update() {
	bool 创建数组 = false;

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	auto* socket3 = f_get输入插座(3);
	_DEF_轴向旋转向量节点_插座类型转换_;
	return false;
}

std::string C_按轴向旋转向量节点::DEF_节点编译函数 {
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();

	bool 创建数组 = false;

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	auto* socket3 = f_get输入插座(3);
	_DEF_轴向旋转向量节点_插座类型转换_;


	if (创建数组) {
		m_Code += DEF_S(S_Vec3Array*);
	}
	else {
		m_Code += DEF_S(vec3);
	}
	m_Code += " " + name + ";\n";

	auto outSocket1 = f_get输出插座(1); 

	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);
	m_Code += socket3->f_构建变量代码(0);


	auto 方式 = f_代码构建_属性变量(m_计算类型, f_getThis节点树());
	if (创建数组) {
		m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "1") + ";\n";
		m_Code += DEF_S(f_math_轴向旋转变换m);
		m_Code += "(" + name + ", " + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + socket3->f_getCode(0) + ", " + 方式 + ");\n";
	}
	else {
		m_Code += name + " = " DEF_S(f_math_轴向旋转变换);
		m_Code += "(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + socket3->f_getCode(0) + ", " + 方式 + ");\n";
	}

	m_Code += m_ReleaseCode;
	m_Code += "}\n";


	outSocket1->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_按轴向旋转向量节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);

	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_按轴向旋转向量节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建按轴向旋转向量节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_按轴向旋转向量节点(ctx);
}

C_节点基类* f_node_加载按轴向旋转向量节点(S_设备环境& ctx, FILE* f) {
	C_按轴向旋转向量节点* node = new C_按轴向旋转向量节点(ctx);
	return node;
}

void f_node_保存按轴向旋转向量节点(C_节点基类* n, FILE* f) {
	C_按轴向旋转向量节点* node = dynamic_cast<C_按轴向旋转向量节点*>(n);
}




C_平面到点节点::C_平面到点节点(S_设备环境& ctx) : C_节点基类(DEF_平面到点节点) {
	m_Ctx = ctx;
	f_setWName(u"点到平面");

	C_插座基类* socket;
	DEF_创建Vec3插座_I(u"点", nullptr);
	DEF_创建Vec4插座_I(u"平面", nullptr);
	
	DEF_创建F32插座_O(u"距离", nullptr);


	m_计算类型 = f_alloc_EnumProp(nullptr, {
		{u"距离",u""},
		{u"内外",u""},
		}, u"计算方式");
	m_计算类型.m_私有 = true;
}

C_平面到点节点::~C_平面到点节点() {
	f_prop_Release(m_计算类型);
}

#define _DEF_平面到点节点_插座类型转换_                                                      \
if (socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D ||                            \
	socket2->f_get接入的数据类型() == E_值类型::e_Type_Vec4_1D) 创建数组 = true;             \
if (!socket1->f_isLink() && !socket2->f_isLink()) 创建数组 = false;                          \
if (创建数组) {                                                                              \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);   \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec4_1D);   \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32_1D);    \
}                                                                                            \
else {                                                                                       \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);      \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec4);      \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_F32);       \
}                                                                                            \
socket1 = f_get输入插座(1);                                                                  \
socket2 = f_get输入插座(2);                                                                  \


bool C_平面到点节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	auto* outSocket1 = f_get输出插座(1);
	
	bool 创建数组 = false;
	_DEF_平面到点节点_插座类型转换_;

	if (创建数组) {
		f_mat_点到平面距离(DEF_Vec3插座_1D数据(socket1), DEF_Vec4插座_1D数据(socket1), DEF_F32插座_1D数据(outSocket1));
	}
	else {
		DEF_F32插座数据(outSocket1) = f_graph_点到平面距离(DEF_Vec3插座数据(socket1), DEF_Vec4插座数据(socket2));
	}
	
	return false;
}

std::string C_平面到点节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);


	bool 创建数组 = false;
	_DEF_平面到点节点_插座类型转换_;


	if (创建数组) {
		m_Code += DEF_S(S_F32Array*)" " + name + ";\n";
	}
	else {
		m_Code += DEF_S(float32)" " + name + ";\n";
	}
	
	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);

	if (创建数组) {
		m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_F32_1D, "1") + ";\n";
		m_Code += DEF_S(f_mat_点到平面距离)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + name + ");\n";
	}
	else {
		m_Code += name + " = " + DEF_S(f_graph_点到平面距离)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ");\n";
	}
	
	m_Code += m_ReleaseCode;
	m_Code += "}\n";


	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_平面到点节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_平面到点节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建平面向量节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_平面到点节点(ctx);
}

C_节点基类* f_node_加载平面向量节点(S_设备环境& ctx, FILE* f) {
	C_平面到点节点* node = new C_平面到点节点(ctx);
	return node;
}

void		f_node_保存平面向量节点(C_节点基类* n, FILE* f) {
	C_平面到点节点* node = dynamic_cast<C_平面到点节点*>(n);
}




C_平面线段相交节点::C_平面线段相交节点(S_设备环境& ctx) : C_节点基类(DEF_平面线段相交节点) {
	m_Ctx = ctx;
	f_setWName(u"点到平面");

	C_插座基类* socket;
	DEF_创建Vec3_1D插座_I(u"点", nullptr);
	DEF_创建Vec4_1D插座_I(u"平面", nullptr);

	DEF_创建Vec3_1D插座_O(u"交点", nullptr);
}

C_平面线段相交节点::~C_平面线段相交节点() {
}

#define _DEF_平面线段相交节点_插座类型转换_                                                  \
if (socket1->f_get接入的数据类型() == E_值类型::e_Type_Vec3_1D ||                            \
	socket2->f_get接入的数据类型() == E_值类型::e_Type_Vec4_1D) 创建数组 = true;             \
if (!socket1->f_isLink() && !socket2->f_isLink()) 创建数组 = false;                          \
if (创建数组) {                                                                              \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3_1D);   \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec4_1D);   \
    f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3_1D);   \
}                                                                                            \
else {                                                                                       \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 1, E_值类型::e_Type_Vec3);      \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输入, 2, E_值类型::e_Type_Vec4);      \
	f_su_切换后端插座类型(this, E_插座方向::e_插座Type_输出, 1, E_值类型::e_Type_Vec3);      \
}                                                                                            \
socket1 = f_get输入插座(1);                                                                  \
socket2 = f_get输入插座(2);                                                                  \


bool C_平面线段相交节点::f_update() {
	return false;
}

std::string C_平面线段相交节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);


	m_Code += DEF_S(S_Vec3Array*)" " + name + ";\n";
	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);

	m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "1") + ";\n";
	m_Code += DEF_S(f_mat_射线平面相交)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + name + ");\n";
	//if (创建数组) {
	//	m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "1") + ";\n";
	//	m_Code += DEF_S(f_mat_射线平面相交)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + name + ");\n";
	//}
	//else {
	//	m_Code += name + " = " + DEF_S(f_graph_射线相交平面2)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ");\n";
	//}

	m_Code += m_ReleaseCode;
	m_Code += "}\n";


	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;
		m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		//if (创建数组) {
		//	m_区域父节点->m_ReleaseCode += f_代码构建_销毁数组(name);
		//}
		return "";
	}
	//if (创建数组) {
	//	释放 += f_代码构建_销毁数组(name);
	//}
	释放 += f_代码构建_销毁数组(name);
	return m_Code;
}

void C_平面线段相交节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		//下一次读取数据指针 = f_prop_Load(m_计算方式, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_平面线段相交节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	//f_prop_Save(m_计算方式, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建线段平面相交节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_平面线段相交节点(ctx);
}

C_节点基类* f_node_加载线段平面相交节点(S_设备环境& ctx, FILE* f) {
	C_平面线段相交节点* node = new C_平面线段相交节点(ctx);
	return node;
}

void f_node_保存线段平面相交节点(C_节点基类* n, FILE* f) {
	C_平面线段相交节点* node = dynamic_cast<C_平面线段相交节点*>(n);
}






C_坐标转索引节点::C_坐标转索引节点(S_设备环境& ctx) : C_节点基类(DEF_坐标转索引节点) {
	m_Ctx = ctx;
	f_setWName(u"坐标转索引");

	C_插座基类* socket;
	DEF_创建iVec3插座_I(u"坐标", nullptr);
	DEF_创建iVec3插座_I(u"维度", nullptr);

	DEF_创建UI32插座_O(u"索引", nullptr);


	m_计算类型 = f_alloc_EnumProp(nullptr, 轴向平面icos, u"平面朝向");
	m_计算类型.m_私有 = true;

}

C_坐标转索引节点::~C_坐标转索引节点() {
	f_prop_Release(m_计算类型);
}

bool C_坐标转索引节点::f_update() {
	return false;
}

std::string C_坐标转索引节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);


	bool 创建数组 = false;

	auto 接入的数据类型1 = socket1->f_get接入的数据类型();
	auto 接入的数据类型2 = socket2->f_get接入的数据类型();

	if (!socket1->f_isLink() && !socket2->f_isLink()) {
		goto To_单值插座构建;
	}

	if (f_代码构建_是否为数组(接入的数据类型1) || f_代码构建_是否为数组(接入的数据类型2)) {
		f_su_切换后端插座类型(this, e_插座Type_输入, 1, E_值类型::e_Type_iVec3_1D);
		f_su_切换后端插座类型(this, e_插座Type_输入, 2, E_值类型::e_Type_iVec3_1D);
		f_su_切换后端插座类型(this, e_插座Type_输出, 1, E_值类型::e_Type_UI32_1D);

		创建数组 = true;
	}
	else {
		To_单值插座构建:
		f_su_切换后端插座类型(this, e_插座Type_输入, 1, E_值类型::e_Type_iVec3);
		f_su_切换后端插座类型(this, e_插座Type_输入, 2, E_值类型::e_Type_iVec3);
		f_su_切换后端插座类型(this, e_插座Type_输出, 1, E_值类型::e_Type_UI32);
	}
	socket1 = f_get输入插座(1);
	socket2 = f_get输入插座(2);


	if (创建数组) {
		m_Code += DEF_S(S_UI32Array*)" " + name + ";\n";
	}
	else {
		m_Code += DEF_S(uint32)" " + name + ";\n";
	}

	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);

	auto 计算类型 = f_代码构建_属性变量(m_计算类型, f_getThis节点树());
	if (创建数组) {
		m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_UI32_1D, "1");
		m_Code += DEF_S(f_JIT_坐标转索引m)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + name + ", " + 计算类型 + ");\n";
	}
	else {
		m_Code += name + " = " + DEF_S(f_JIT_坐标转索引)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + 计算类型 + ");\n";
	}

	m_Code += m_ReleaseCode;
	m_Code += "}\n";


	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_坐标转索引节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_坐标转索引节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建坐标转索引节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_坐标转索引节点(ctx);
}

C_节点基类* f_node_加载坐标转索引节点(S_设备环境& ctx, FILE* f) {
	C_坐标转索引节点* node = new C_坐标转索引节点(ctx);
	return node;
}

void f_node_保存坐标转索引节点(C_节点基类* n, FILE* f) {
	C_坐标转索引节点* node = dynamic_cast<C_坐标转索引节点*>(n);
}






C_索引转坐标节点::C_索引转坐标节点(S_设备环境& ctx) : C_节点基类(DEF_索引转坐标节点) {
	m_Ctx = ctx;
	f_setWName(u"索引转坐标");

	C_插座基类* socket;
	DEF_创建UI32插座_I(u"索引", nullptr);
	DEF_创建iVec3插座_I(u"维度", nullptr);

	DEF_创建iVec3插座_O(u"坐标", nullptr);


	m_计算类型 = f_alloc_EnumProp(nullptr, 轴向平面icos, u"平面朝向");
	m_计算类型.m_私有 = true;

}

C_索引转坐标节点::~C_索引转坐标节点() {
	f_prop_Release(m_计算类型);
}

bool C_索引转坐标节点::f_update() {
	return false;
}

std::string C_索引转坐标节点::DEF_节点编译函数{
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();

	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);


	bool 创建数组 = false;

	if (创建数组) {
		m_Code += DEF_S(S_iVec3Array*)" " + name + ";\n";
	}
	else {
		m_Code += DEF_S(ivec3)" " + name + ";\n";
	}

	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);
	m_Code += socket2->f_构建变量代码(0);

	auto 计算类型 = f_代码构建_属性变量(m_计算类型, f_getThis节点树());
	if (创建数组) {
		m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_iVec3_1D, "1");
		m_Code += DEF_S(f_JIT_索引转坐标m)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + name + ", " + 计算类型 + ");\n";
	}
	else {
		m_Code += name + " = " + DEF_S(f_JIT_索引转坐标)"(" + socket1->f_getCode(0) + ", " + socket2->f_getCode(0) + ", " + 计算类型 + ");\n";
	}

	m_Code += m_ReleaseCode;
	m_Code += "}\n";


	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		if (创建数组) {
			m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		}
		return "";
	}
	if (创建数组) {
		释放 += f_代码构建_销毁数组(name);
	}
	return m_Code;
}

void C_索引转坐标节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_索引转坐标节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建索引转坐标节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_索引转坐标节点(ctx);
}

C_节点基类* f_node_加载索引转坐标节点(S_设备环境& ctx, FILE* f) {
	C_索引转坐标节点* node = new C_索引转坐标节点(ctx);
	return node;
}

void f_node_保存索引转坐标节点(C_节点基类* n, FILE* f) {
	C_索引转坐标节点* node = dynamic_cast<C_索引转坐标节点*>(n);
}



C_线段方向节点::C_线段方向节点(S_设备环境& ctx) : C_节点基类(DEF_线段方向节点, E_节点类型::e_节点Type_计算) {
	m_Ctx = ctx;
	f_setWName(u"线段方向");

	DEF_创建Vec3_1D插座_I(u"线段端点");

	DEF_创建Vec3_1D插座_O(u"方向");


	m_计算类型 = f_alloc_EnumProp(nullptr, 轴向平面icos, u"计算方式");
	m_计算类型.m_私有 = true;
}

C_线段方向节点::~C_线段方向节点() {
	f_prop_Release(m_计算类型);
}

bool C_线段方向节点::f_update() {
	return false;
}

std::string C_线段方向节点::DEF_节点编译函数 {
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();

	auto* socket1 = f_get输入插座(1);
	bool 创建数组 = false;

	m_Code += DEF_S(S_Vec3Array*)" " + name + ";\n";

	m_Code += "{\n";
	m_Code += socket1->f_构建变量代码(0);

	auto 计算类型 = f_代码构建_属性变量(m_计算类型, f_getThis节点树());

	m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "1");
	m_Code += DEF_S(f_surface_线段方向)"(" + socket1->f_getCode(0) + ", " + name + ");\n";

	m_Code += m_ReleaseCode;
	m_Code += "}\n";

	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		return "";
	}
	释放 += f_代码构建_销毁数组(name);
	return m_Code;
}

void C_线段方向节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_线段方向节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	f_prop_Save(m_计算类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建线段方向节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_线段方向节点(ctx);
}

C_节点基类* f_node_加载线段方向节点(S_设备环境& ctx, FILE* f) {
	C_线段方向节点* node = new C_线段方向节点(ctx);
	return node;
}

void f_node_保存线段方向节点(C_节点基类* n, FILE* f) {
	C_线段方向节点* node = dynamic_cast<C_线段方向节点*>(n);
}




C_色相饱和度节点::C_色相饱和度节点(S_设备环境& ctx) : C_节点基类(DEF_色相饱和度节点, E_节点类型::e_节点Type_颜色) {
	m_Ctx = ctx;
	f_setWName(u"色相饱和度");

	DEF_创建颜色插座_I(u"颜色");
	DEF_创建F32插座_v1_I(u"色相");
	DEF_创建F32插座_v1_I(u"饱和");
	DEF_创建F32插座_v1_I(u"亮度");

	DEF_创建颜色插座_O(u"颜色");



	f_构建代码_构建GPU插座变量(*f_get输入插座(1));
	f_构建代码_构建GPU插座变量(*f_get输入插座(2));
	f_构建代码_构建GPU插座变量(*f_get输入插座(3));
	f_构建代码_构建GPU插座变量(*f_get输入插座(4));

}

C_色相饱和度节点::~C_色相饱和度节点() {
	f_构建代码_释放GPU插座变量(*f_get输入插座(1));
	f_构建代码_释放GPU插座变量(*f_get输入插座(2));
	f_构建代码_释放GPU插座变量(*f_get输入插座(3));
	f_构建代码_释放GPU插座变量(*f_get输入插座(4));
}

bool C_色相饱和度节点::f_update() {
	return false;
}

std::string C_色相饱和度节点::DEF_节点编译函数 {
	m_Code = "";
	m_ReleaseCode = "";
	std::string name = f_getName();
	auto* rt = f_getThis节点树();

	bool 创建数组 = false;

	m_Code += DEF_S(vec4)" " + name + ";\n";


	auto* socket1 = f_get输入插座(1);
	auto* socket2 = f_get输入插座(2);
	auto* socket3 = f_get输入插座(3);
	auto* socket4 = f_get输入插座(4);

	socket1->f_upGPU块(0);
	socket2->f_upGPU块(0);
	socket3->f_upGPU块(0);
	socket4->f_upGPU块(0);

	m_Code += "{\n";

	switch (rt->m_树类型) {
		case E_节点树类型::e_type_几何着色节点树:
		case E_节点树类型::e_type_并行节点树:
		case E_节点树类型::e_type_着色节点树: {
			m_Code += socket1->f_构建变量代码(0);
			m_Code += socket2->f_构建变量代码(0);
			m_Code += socket3->f_构建变量代码(0);
			m_Code += socket4->f_构建变量代码(0);

			m_Code += name + " = " + socket1->f_getCode(0) + ";\n";
			break;
		}
		default: {
			break;
		}
	}

	
	//m_Code += socket1->f_构建变量代码(0);
	//
	//m_Code += name + " = " + f_代码构建_创建Array(E_值类型::e_Type_Vec3_1D, "1");
	//m_Code += DEF_S(f_surface_线段方向)"(" + socket1->f_getCode(0) + ", " + name + ");\n";
	//
	//m_Code += m_ReleaseCode;
	m_Code += "}\n";

	f_get输出插座(1)->f_setCode(name);
	if (m_区域父节点) {
		m_区域父节点->m_Code += m_Code;

		//m_区域父节点->m_ReleaseCode.insert(0, f_代码构建_销毁数组(name));
		return "";
	}
	//释放 += f_代码构建_销毁数组(name);
	return m_Code;
}

void C_色相饱和度节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	S_文件块 文件块 = f_file_读取文件块(f);
	if (文件块.m_块类型 == E_节点工程文件块类型::e_工程文件块_节点实例属性) {
		const uint8* 下一次读取数据指针 = 文件块.m_data;

		//下一次读取数据指针 = f_prop_Load(m_计算类型, 下一次读取数据指针);
	}
	free(文件块.m_data);
}

void C_色相饱和度节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	auto 文件块 = f_文件块_创建(E_节点工程文件块类型::e_工程文件块_节点实例属性, S_引擎配置::g_文件版本号);
	S_UI8Array* 块 = (S_UI8Array*)f_core_array_new(0, sizeof(uint8));

	//f_prop_Save(m_计算类型, 块);

	f_file_保存文件块(f, 文件块, 块);
}

C_节点基类* f_node_创建色相饱和度节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_色相饱和度节点(ctx);
}

C_节点基类* f_node_加载色相饱和度节点(S_设备环境& ctx, FILE* f) {
	C_色相饱和度节点* node = new C_色相饱和度节点(ctx);
	return node;
}

void f_node_保存色相饱和度节点(C_节点基类* n, FILE* f) {
	C_色相饱和度节点* node = dynamic_cast<C_色相饱和度节点*>(n);
}

